EditeurPanovisu 3.1.0
Éditeur de visites virtuelles 360° Panovisu
Chargement...
Recherche...
Aucune correspondance
three.js
Aller à la documentation de ce fichier.
1console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated with r150+, and will be removed with r160. Please use ES Modules or alternatives: https://threejs.org/docs/index.html#manual/en/introduction/Installation' );
7(function (global, factory) {
8 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
9 typeof define === 'function' && define.amd ? define(['exports'], factory) :
10 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.THREE = {}));
11})(this, (function (exports) { 'use strict';
12
13 const REVISION = '160';
14
15 const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
16 const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
17 const CullFaceNone = 0;
18 const CullFaceBack = 1;
19 const CullFaceFront = 2;
20 const CullFaceFrontBack = 3;
21 const BasicShadowMap = 0;
22 const PCFShadowMap = 1;
23 const PCFSoftShadowMap = 2;
24 const VSMShadowMap = 3;
25 const FrontSide = 0;
26 const BackSide = 1;
27 const DoubleSide = 2;
28 const TwoPassDoubleSide = 2; // r149
29 const NoBlending = 0;
30 const NormalBlending = 1;
31 const AdditiveBlending = 2;
32 const SubtractiveBlending = 3;
33 const MultiplyBlending = 4;
34 const CustomBlending = 5;
35 const AddEquation = 100;
36 const SubtractEquation = 101;
37 const ReverseSubtractEquation = 102;
38 const MinEquation = 103;
39 const MaxEquation = 104;
40 const ZeroFactor = 200;
41 const OneFactor = 201;
42 const SrcColorFactor = 202;
43 const OneMinusSrcColorFactor = 203;
44 const SrcAlphaFactor = 204;
45 const OneMinusSrcAlphaFactor = 205;
46 const DstAlphaFactor = 206;
47 const OneMinusDstAlphaFactor = 207;
48 const DstColorFactor = 208;
49 const OneMinusDstColorFactor = 209;
50 const SrcAlphaSaturateFactor = 210;
51 const ConstantColorFactor = 211;
53 const ConstantAlphaFactor = 213;
55 const NeverDepth = 0;
56 const AlwaysDepth = 1;
57 const LessDepth = 2;
58 const LessEqualDepth = 3;
59 const EqualDepth = 4;
60 const GreaterEqualDepth = 5;
61 const GreaterDepth = 6;
62 const NotEqualDepth = 7;
63 const MultiplyOperation = 0;
64 const MixOperation = 1;
65 const AddOperation = 2;
66 const NoToneMapping = 0;
67 const LinearToneMapping = 1;
68 const ReinhardToneMapping = 2;
69 const CineonToneMapping = 3;
70 const ACESFilmicToneMapping = 4;
71 const CustomToneMapping = 5;
72 const AgXToneMapping = 6;
73 const AttachedBindMode = 'attached';
74 const DetachedBindMode = 'detached';
75
76 const UVMapping = 300;
77 const CubeReflectionMapping = 301;
78 const CubeRefractionMapping = 302;
81 const CubeUVReflectionMapping = 306;
82 const RepeatWrapping = 1000;
83 const ClampToEdgeWrapping = 1001;
84 const MirroredRepeatWrapping = 1002;
85 const NearestFilter = 1003;
86 const NearestMipmapNearestFilter = 1004;
87 const NearestMipMapNearestFilter = 1004;
88 const NearestMipmapLinearFilter = 1005;
89 const NearestMipMapLinearFilter = 1005;
90 const LinearFilter = 1006;
91 const LinearMipmapNearestFilter = 1007;
92 const LinearMipMapNearestFilter = 1007;
93 const LinearMipmapLinearFilter = 1008;
94 const LinearMipMapLinearFilter = 1008;
95 const UnsignedByteType = 1009;
96 const ByteType = 1010;
97 const ShortType = 1011;
98 const UnsignedShortType = 1012;
99 const IntType = 1013;
100 const UnsignedIntType = 1014;
101 const FloatType = 1015;
102 const HalfFloatType = 1016;
103 const UnsignedShort4444Type = 1017;
104 const UnsignedShort5551Type = 1018;
105 const UnsignedInt248Type = 1020;
106 const AlphaFormat = 1021;
107 const RGBAFormat = 1023;
108 const LuminanceFormat = 1024;
109 const LuminanceAlphaFormat = 1025;
110 const DepthFormat = 1026;
111 const DepthStencilFormat = 1027;
112 const RedFormat = 1028;
113 const RedIntegerFormat = 1029;
114 const RGFormat = 1030;
115 const RGIntegerFormat = 1031;
116 const RGBAIntegerFormat = 1033;
117
118 const RGB_S3TC_DXT1_Format = 33776;
119 const RGBA_S3TC_DXT1_Format = 33777;
120 const RGBA_S3TC_DXT3_Format = 33778;
121 const RGBA_S3TC_DXT5_Format = 33779;
122 const RGB_PVRTC_4BPPV1_Format = 35840;
123 const RGB_PVRTC_2BPPV1_Format = 35841;
124 const RGBA_PVRTC_4BPPV1_Format = 35842;
125 const RGBA_PVRTC_2BPPV1_Format = 35843;
126 const RGB_ETC1_Format = 36196;
127 const RGB_ETC2_Format = 37492;
128 const RGBA_ETC2_EAC_Format = 37496;
129 const RGBA_ASTC_4x4_Format = 37808;
130 const RGBA_ASTC_5x4_Format = 37809;
131 const RGBA_ASTC_5x5_Format = 37810;
132 const RGBA_ASTC_6x5_Format = 37811;
133 const RGBA_ASTC_6x6_Format = 37812;
134 const RGBA_ASTC_8x5_Format = 37813;
135 const RGBA_ASTC_8x6_Format = 37814;
136 const RGBA_ASTC_8x8_Format = 37815;
137 const RGBA_ASTC_10x5_Format = 37816;
138 const RGBA_ASTC_10x6_Format = 37817;
139 const RGBA_ASTC_10x8_Format = 37818;
140 const RGBA_ASTC_10x10_Format = 37819;
141 const RGBA_ASTC_12x10_Format = 37820;
142 const RGBA_ASTC_12x12_Format = 37821;
143 const RGBA_BPTC_Format = 36492;
144 const RGB_BPTC_SIGNED_Format = 36494;
145 const RGB_BPTC_UNSIGNED_Format = 36495;
146 const RED_RGTC1_Format = 36283;
147 const SIGNED_RED_RGTC1_Format = 36284;
148 const RED_GREEN_RGTC2_Format = 36285;
149 const SIGNED_RED_GREEN_RGTC2_Format = 36286;
150 const LoopOnce = 2200;
151 const LoopRepeat = 2201;
152 const LoopPingPong = 2202;
153 const InterpolateDiscrete = 2300;
154 const InterpolateLinear = 2301;
155 const InterpolateSmooth = 2302;
156 const ZeroCurvatureEnding = 2400;
157 const ZeroSlopeEnding = 2401;
158 const WrapAroundEnding = 2402;
159 const NormalAnimationBlendMode = 2500;
160 const AdditiveAnimationBlendMode = 2501;
161 const TrianglesDrawMode = 0;
162 const TriangleStripDrawMode = 1;
163 const TriangleFanDrawMode = 2;
165 const LinearEncoding = 3000;
167 const sRGBEncoding = 3001;
168 const BasicDepthPacking = 3200;
169 const RGBADepthPacking = 3201;
170 const TangentSpaceNormalMap = 0;
171 const ObjectSpaceNormalMap = 1;
172
173 // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available.
174 const NoColorSpace = '';
175 const SRGBColorSpace = 'srgb';
176 const LinearSRGBColorSpace = 'srgb-linear';
177 const DisplayP3ColorSpace = 'display-p3';
178 const LinearDisplayP3ColorSpace = 'display-p3-linear';
179
180 const LinearTransfer = 'linear';
181 const SRGBTransfer = 'srgb';
182
183 const Rec709Primaries = 'rec709';
184 const P3Primaries = 'p3';
185
186 const ZeroStencilOp = 0;
187 const KeepStencilOp = 7680;
188 const ReplaceStencilOp = 7681;
189 const IncrementStencilOp = 7682;
190 const DecrementStencilOp = 7683;
191 const IncrementWrapStencilOp = 34055;
192 const DecrementWrapStencilOp = 34056;
193 const InvertStencilOp = 5386;
194
195 const NeverStencilFunc = 512;
196 const LessStencilFunc = 513;
197 const EqualStencilFunc = 514;
198 const LessEqualStencilFunc = 515;
199 const GreaterStencilFunc = 516;
200 const NotEqualStencilFunc = 517;
201 const GreaterEqualStencilFunc = 518;
202 const AlwaysStencilFunc = 519;
203
204 const NeverCompare = 512;
205 const LessCompare = 513;
206 const EqualCompare = 514;
207 const LessEqualCompare = 515;
208 const GreaterCompare = 516;
209 const NotEqualCompare = 517;
210 const GreaterEqualCompare = 518;
211 const AlwaysCompare = 519;
212
213 const StaticDrawUsage = 35044;
214 const DynamicDrawUsage = 35048;
215 const StreamDrawUsage = 35040;
216 const StaticReadUsage = 35045;
217 const DynamicReadUsage = 35049;
218 const StreamReadUsage = 35041;
219 const StaticCopyUsage = 35046;
220 const DynamicCopyUsage = 35050;
221 const StreamCopyUsage = 35042;
222
223 const GLSL1 = '100';
224 const GLSL3 = '300 es';
225
226 const _SRGBAFormat = 1035; // fallback for WebGL 1
227
228 const WebGLCoordinateSystem = 2000;
229 const WebGPUCoordinateSystem = 2001;
230
235 class EventDispatcher {
236
237 addEventListener( type, listener ) {
238
239 if ( this._listeners === undefined ) this._listeners = {};
240
241 const listeners = this._listeners;
242
243 if ( listeners[ type ] === undefined ) {
244
245 listeners[ type ] = [];
246
247 }
248
249 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
250
251 listeners[ type ].push( listener );
252
253 }
254
255 }
256
257 hasEventListener( type, listener ) {
258
259 if ( this._listeners === undefined ) return false;
260
261 const listeners = this._listeners;
262
263 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
264
265 }
266
268
269 if ( this._listeners === undefined ) return;
270
271 const listeners = this._listeners;
272 const listenerArray = listeners[ type ];
273
274 if ( listenerArray !== undefined ) {
275
276 const index = listenerArray.indexOf( listener );
277
278 if ( index !== - 1 ) {
279
280 listenerArray.splice( index, 1 );
281
282 }
283
284 }
285
286 }
287
289
290 if ( this._listeners === undefined ) return;
291
292 const listeners = this._listeners;
293 const listenerArray = listeners[ event.type ];
294
295 if ( listenerArray !== undefined ) {
296
297 event.target = this;
298
299 // Make a copy, in case listeners are removed while iterating.
300 const array = listenerArray.slice( 0 );
301
302 for ( let i = 0, l = array.length; i < l; i ++ ) {
303
304 array[ i ].call( this, event );
305
306 }
307
308 event.target = null;
309
310 }
311
312 }
313
314 }
315
316 const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ];
317
318 let _seed = 1234567;
319
320
321 const DEG2RAD = Math.PI / 180;
322 const RAD2DEG = 180 / Math.PI;
323
324 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
325 function generateUUID() {
326
327 const d0 = Math.random() * 0xffffffff | 0;
328 const d1 = Math.random() * 0xffffffff | 0;
329 const d2 = Math.random() * 0xffffffff | 0;
330 const d3 = Math.random() * 0xffffffff | 0;
331 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
332 _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
333 _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
334 _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
335
336 // .toLowerCase() here flattens concatenated strings to save heap memory space.
337 return uuid.toLowerCase();
338
339 }
340
341 function clamp( value, min, max ) {
342
343 return Math.max( min, Math.min( max, value ) );
344
345 }
346
347 // compute euclidean modulo of m % n
348 // https://en.wikipedia.org/wiki/Modulo_operation
349 function euclideanModulo( n, m ) {
350
351 return ( ( n % m ) + m ) % m;
352
353 }
354
355 // Linear mapping from range <a1, a2> to range <b1, b2>
356 function mapLinear( x, a1, a2, b1, b2 ) {
357
358 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
359
360 }
361
362 // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
363 function inverseLerp( x, y, value ) {
364
365 if ( x !== y ) {
366
367 return ( value - x ) / ( y - x );
368
369 } else {
370
371 return 0;
372
373 }
374
375 }
376
377 // https://en.wikipedia.org/wiki/Linear_interpolation
378 function lerp( x, y, t ) {
379
380 return ( 1 - t ) * x + t * y;
381
382 }
383
384 // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
385 function damp( x, y, lambda, dt ) {
386
387 return lerp( x, y, 1 - Math.exp( - lambda * dt ) );
388
389 }
390
391 // https://www.desmos.com/calculator/vcsjnyz7x4
392 function pingpong( x, length = 1 ) {
393
394 return length - Math.abs( euclideanModulo( x, length * 2 ) - length );
395
396 }
397
398 // http://en.wikipedia.org/wiki/Smoothstep
399 function smoothstep( x, min, max ) {
400
401 if ( x <= min ) return 0;
402 if ( x >= max ) return 1;
403
404 x = ( x - min ) / ( max - min );
405
406 return x * x * ( 3 - 2 * x );
407
408 }
409
410 function smootherstep( x, min, max ) {
411
412 if ( x <= min ) return 0;
413 if ( x >= max ) return 1;
414
415 x = ( x - min ) / ( max - min );
416
417 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
418
419 }
420
421 // Random integer from <low, high> interval
422 function randInt( low, high ) {
423
424 return low + Math.floor( Math.random() * ( high - low + 1 ) );
425
426 }
427
428 // Random float from <low, high> interval
429 function randFloat( low, high ) {
430
431 return low + Math.random() * ( high - low );
432
433 }
434
435 // Random float from <-range/2, range/2> interval
436 function randFloatSpread( range ) {
437
438 return range * ( 0.5 - Math.random() );
439
440 }
441
442 // Deterministic pseudo-random float in the interval [ 0, 1 ]
443 function seededRandom( s ) {
444
445 if ( s !== undefined ) _seed = s;
446
447 // Mulberry32 generator
448
449 let t = _seed += 0x6D2B79F5;
450
451 t = Math.imul( t ^ t >>> 15, t | 1 );
452
453 t ^= t + Math.imul( t ^ t >>> 7, t | 61 );
454
455 return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;
456
457 }
458
459 function degToRad( degrees ) {
460
461 return degrees * DEG2RAD;
462
463 }
464
465 function radToDeg( radians ) {
466
467 return radians * RAD2DEG;
468
469 }
470
471 function isPowerOfTwo( value ) {
472
473 return ( value & ( value - 1 ) ) === 0 && value !== 0;
474
475 }
476
477 function ceilPowerOfTwo( value ) {
478
479 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
480
481 }
482
483 function floorPowerOfTwo( value ) {
484
485 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
486
487 }
488
489 function setQuaternionFromProperEuler( q, a, b, c, order ) {
490
491 // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
492
493 // rotations are applied to the axes in the order specified by 'order'
494 // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
495 // angles are in radians
496
497 const cos = Math.cos;
498 const sin = Math.sin;
499
500 const c2 = cos( b / 2 );
501 const s2 = sin( b / 2 );
502
503 const c13 = cos( ( a + c ) / 2 );
504 const s13 = sin( ( a + c ) / 2 );
505
506 const c1_3 = cos( ( a - c ) / 2 );
507 const s1_3 = sin( ( a - c ) / 2 );
508
509 const c3_1 = cos( ( c - a ) / 2 );
510 const s3_1 = sin( ( c - a ) / 2 );
511
512 switch ( order ) {
513
514 case 'XYX':
515 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
516 break;
517
518 case 'YZY':
519 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
520 break;
521
522 case 'ZXZ':
523 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
524 break;
525
526 case 'XZX':
527 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
528 break;
529
530 case 'YXY':
531 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
532 break;
533
534 case 'ZYZ':
535 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
536 break;
537
538 default:
539 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );
540
541 }
542
543 }
544
545 function denormalize( value, array ) {
546
547 switch ( array.constructor ) {
548
549 case Float32Array:
550
551 return value;
552
553 case Uint32Array:
554
555 return value / 4294967295.0;
556
557 case Uint16Array:
558
559 return value / 65535.0;
560
561 case Uint8Array:
562
563 return value / 255.0;
564
565 case Int32Array:
566
567 return Math.max( value / 2147483647.0, - 1.0 );
568
569 case Int16Array:
570
571 return Math.max( value / 32767.0, - 1.0 );
572
573 case Int8Array:
574
575 return Math.max( value / 127.0, - 1.0 );
576
577 default:
578
579 throw new Error( 'Invalid component type.' );
580
581 }
582
583 }
584
585 function normalize( value, array ) {
586
587 switch ( array.constructor ) {
588
589 case Float32Array:
590
591 return value;
592
593 case Uint32Array:
594
595 return Math.round( value * 4294967295.0 );
596
597 case Uint16Array:
598
599 return Math.round( value * 65535.0 );
600
601 case Uint8Array:
602
603 return Math.round( value * 255.0 );
604
605 case Int32Array:
606
607 return Math.round( value * 2147483647.0 );
608
609 case Int16Array:
610
611 return Math.round( value * 32767.0 );
612
613 case Int8Array:
614
615 return Math.round( value * 127.0 );
616
617 default:
618
619 throw new Error( 'Invalid component type.' );
620
621 }
622
623 }
624
625 const MathUtils = {
629 clamp: clamp,
633 lerp: lerp,
634 damp: damp,
642 degToRad: degToRad,
650 };
651
652 class Vector2 {
653
654 constructor( x = 0, y = 0 ) {
655
656 Vector2.prototype.isVector2 = true;
657
658 this.x = x;
659 this.y = y;
660
661 }
662
663 get width() {
664
665 return this.x;
666
667 }
668
669 set width( value ) {
670
671 this.x = value;
672
673 }
674
675 get height() {
676
677 return this.y;
678
679 }
680
681 set height( value ) {
682
683 this.y = value;
684
685 }
686
687 set( x, y ) {
688
689 this.x = x;
690 this.y = y;
691
692 return this;
693
694 }
695
696 setScalar( scalar ) {
697
698 this.x = scalar;
699 this.y = scalar;
700
701 return this;
702
703 }
704
705 setX( x ) {
706
707 this.x = x;
708
709 return this;
710
711 }
712
713 setY( y ) {
714
715 this.y = y;
716
717 return this;
718
719 }
720
722
723 switch ( index ) {
724
725 case 0: this.x = value; break;
726 case 1: this.y = value; break;
727 default: throw new Error( 'index is out of range: ' + index );
728
729 }
730
731 return this;
732
733 }
734
736
737 switch ( index ) {
738
739 case 0: return this.x;
740 case 1: return this.y;
741 default: throw new Error( 'index is out of range: ' + index );
742
743 }
744
745 }
746
747 clone() {
748
749 return new this.constructor( this.x, this.y );
750
751 }
752
753 copy( v ) {
754
755 this.x = v.x;
756 this.y = v.y;
757
758 return this;
759
760 }
761
762 add( v ) {
763
764 this.x += v.x;
765 this.y += v.y;
766
767 return this;
768
769 }
770
771 addScalar( s ) {
772
773 this.x += s;
774 this.y += s;
775
776 return this;
777
778 }
779
780 addVectors( a, b ) {
781
782 this.x = a.x + b.x;
783 this.y = a.y + b.y;
784
785 return this;
786
787 }
788
789 addScaledVector( v, s ) {
790
791 this.x += v.x * s;
792 this.y += v.y * s;
793
794 return this;
795
796 }
797
798 sub( v ) {
799
800 this.x -= v.x;
801 this.y -= v.y;
802
803 return this;
804
805 }
806
807 subScalar( s ) {
808
809 this.x -= s;
810 this.y -= s;
811
812 return this;
813
814 }
815
816 subVectors( a, b ) {
817
818 this.x = a.x - b.x;
819 this.y = a.y - b.y;
820
821 return this;
822
823 }
824
825 multiply( v ) {
826
827 this.x *= v.x;
828 this.y *= v.y;
829
830 return this;
831
832 }
833
835
836 this.x *= scalar;
837 this.y *= scalar;
838
839 return this;
840
841 }
842
843 divide( v ) {
844
845 this.x /= v.x;
846 this.y /= v.y;
847
848 return this;
849
850 }
851
853
854 return this.multiplyScalar( 1 / scalar );
855
856 }
857
858 applyMatrix3( m ) {
859
860 const x = this.x, y = this.y;
861 const e = m.elements;
862
863 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
864 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
865
866 return this;
867
868 }
869
870 min( v ) {
871
872 this.x = Math.min( this.x, v.x );
873 this.y = Math.min( this.y, v.y );
874
875 return this;
876
877 }
878
879 max( v ) {
880
881 this.x = Math.max( this.x, v.x );
882 this.y = Math.max( this.y, v.y );
883
884 return this;
885
886 }
887
888 clamp( min, max ) {
889
890 // assumes min < max, componentwise
891
892 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
893 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
894
895 return this;
896
897 }
898
900
901 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
902 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
903
904 return this;
905
906 }
907
908 clampLength( min, max ) {
909
910 const length = this.length();
911
912 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
913
914 }
915
916 floor() {
917
918 this.x = Math.floor( this.x );
919 this.y = Math.floor( this.y );
920
921 return this;
922
923 }
924
925 ceil() {
926
927 this.x = Math.ceil( this.x );
928 this.y = Math.ceil( this.y );
929
930 return this;
931
932 }
933
934 round() {
935
936 this.x = Math.round( this.x );
937 this.y = Math.round( this.y );
938
939 return this;
940
941 }
942
943 roundToZero() {
944
945 this.x = Math.trunc( this.x );
946 this.y = Math.trunc( this.y );
947
948 return this;
949
950 }
951
952 negate() {
953
954 this.x = - this.x;
955 this.y = - this.y;
956
957 return this;
958
959 }
960
961 dot( v ) {
962
963 return this.x * v.x + this.y * v.y;
964
965 }
966
967 cross( v ) {
968
969 return this.x * v.y - this.y * v.x;
970
971 }
972
973 lengthSq() {
974
975 return this.x * this.x + this.y * this.y;
976
977 }
978
979 length() {
980
981 return Math.sqrt( this.x * this.x + this.y * this.y );
982
983 }
984
986
987 return Math.abs( this.x ) + Math.abs( this.y );
988
989 }
990
991 normalize() {
992
993 return this.divideScalar( this.length() || 1 );
994
995 }
996
997 angle() {
998
999 // computes the angle in radians with respect to the positive x-axis
1000
1001 const angle = Math.atan2( - this.y, - this.x ) + Math.PI;
1002
1003 return angle;
1004
1005 }
1006
1007 angleTo( v ) {
1008
1009 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
1010
1011 if ( denominator === 0 ) return Math.PI / 2;
1012
1013 const theta = this.dot( v ) / denominator;
1014
1015 // clamp, to handle numerical problems
1016
1017 return Math.acos( clamp( theta, - 1, 1 ) );
1018
1019 }
1020
1021 distanceTo( v ) {
1022
1023 return Math.sqrt( this.distanceToSquared( v ) );
1024
1025 }
1026
1027 distanceToSquared( v ) {
1028
1029 const dx = this.x - v.x, dy = this.y - v.y;
1030 return dx * dx + dy * dy;
1031
1032 }
1033
1035
1036 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
1037
1038 }
1039
1040 setLength( length ) {
1041
1042 return this.normalize().multiplyScalar( length );
1043
1044 }
1045
1046 lerp( v, alpha ) {
1047
1048 this.x += ( v.x - this.x ) * alpha;
1049 this.y += ( v.y - this.y ) * alpha;
1050
1051 return this;
1052
1053 }
1054
1055 lerpVectors( v1, v2, alpha ) {
1056
1057 this.x = v1.x + ( v2.x - v1.x ) * alpha;
1058 this.y = v1.y + ( v2.y - v1.y ) * alpha;
1059
1060 return this;
1061
1062 }
1063
1064 equals( v ) {
1065
1066 return ( ( v.x === this.x ) && ( v.y === this.y ) );
1067
1068 }
1069
1070 fromArray( array, offset = 0 ) {
1071
1072 this.x = array[ offset ];
1073 this.y = array[ offset + 1 ];
1074
1075 return this;
1076
1077 }
1078
1079 toArray( array = [], offset = 0 ) {
1080
1081 array[ offset ] = this.x;
1082 array[ offset + 1 ] = this.y;
1083
1084 return array;
1085
1086 }
1087
1089
1090 this.x = attribute.getX( index );
1091 this.y = attribute.getY( index );
1092
1093 return this;
1094
1095 }
1096
1098
1099 const c = Math.cos( angle ), s = Math.sin( angle );
1100
1101 const x = this.x - center.x;
1102 const y = this.y - center.y;
1103
1104 this.x = x * c - y * s + center.x;
1105 this.y = x * s + y * c + center.y;
1106
1107 return this;
1108
1109 }
1110
1111 random() {
1112
1113 this.x = Math.random();
1114 this.y = Math.random();
1115
1116 return this;
1117
1118 }
1119
1120 *[ Symbol.iterator ]() {
1121
1122 yield this.x;
1123 yield this.y;
1124
1125 }
1126
1127 }
1128
1129 class Matrix3 {
1130
1131 constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1132
1133 Matrix3.prototype.isMatrix3 = true;
1134
1135 this.elements = [
1136
1137 1, 0, 0,
1138 0, 1, 0,
1139 0, 0, 1
1140
1141 ];
1142
1143 if ( n11 !== undefined ) {
1144
1145 this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
1146
1147 }
1148
1149 }
1150
1151 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
1152
1153 const te = this.elements;
1154
1155 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
1156 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
1157 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
1158
1159 return this;
1160
1161 }
1162
1163 identity() {
1164
1165 this.set(
1166
1167 1, 0, 0,
1168 0, 1, 0,
1169 0, 0, 1
1170
1171 );
1172
1173 return this;
1174
1175 }
1176
1177 copy( m ) {
1178
1179 const te = this.elements;
1180 const me = m.elements;
1181
1182 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
1183 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
1184 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
1185
1186 return this;
1187
1188 }
1189
1191
1192 xAxis.setFromMatrix3Column( this, 0 );
1193 yAxis.setFromMatrix3Column( this, 1 );
1194 zAxis.setFromMatrix3Column( this, 2 );
1195
1196 return this;
1197
1198 }
1199
1200 setFromMatrix4( m ) {
1201
1202 const me = m.elements;
1203
1204 this.set(
1205
1206 me[ 0 ], me[ 4 ], me[ 8 ],
1207 me[ 1 ], me[ 5 ], me[ 9 ],
1208 me[ 2 ], me[ 6 ], me[ 10 ]
1209
1210 );
1211
1212 return this;
1213
1214 }
1215
1216 multiply( m ) {
1217
1218 return this.multiplyMatrices( this, m );
1219
1220 }
1221
1222 premultiply( m ) {
1223
1224 return this.multiplyMatrices( m, this );
1225
1226 }
1227
1228 multiplyMatrices( a, b ) {
1229
1230 const ae = a.elements;
1231 const be = b.elements;
1232 const te = this.elements;
1233
1234 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
1235 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
1236 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
1237
1238 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
1239 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
1240 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
1241
1242 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
1243 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
1244 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
1245
1246 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
1247 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
1248 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
1249
1250 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
1251 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
1252 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
1253
1254 return this;
1255
1256 }
1257
1258 multiplyScalar( s ) {
1259
1260 const te = this.elements;
1261
1262 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
1263 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
1264 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
1265
1266 return this;
1267
1268 }
1269
1270 determinant() {
1271
1272 const te = this.elements;
1273
1274 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
1275 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
1276 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
1277
1278 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
1279
1280 }
1281
1282 invert() {
1283
1284 const te = this.elements,
1285
1286 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],
1287 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],
1288 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],
1289
1290 t11 = n33 * n22 - n32 * n23,
1291 t12 = n32 * n13 - n33 * n12,
1292 t13 = n23 * n12 - n22 * n13,
1293
1294 det = n11 * t11 + n21 * t12 + n31 * t13;
1295
1296 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
1297
1298 const detInv = 1 / det;
1299
1300 te[ 0 ] = t11 * detInv;
1301 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
1302 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
1303
1304 te[ 3 ] = t12 * detInv;
1305 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
1306 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
1307
1308 te[ 6 ] = t13 * detInv;
1309 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
1310 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
1311
1312 return this;
1313
1314 }
1315
1316 transpose() {
1317
1318 let tmp;
1319 const m = this.elements;
1320
1321 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
1322 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
1323 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
1324
1325 return this;
1326
1327 }
1328
1330
1331 return this.setFromMatrix4( matrix4 ).invert().transpose();
1332
1333 }
1334
1336
1337 const m = this.elements;
1338
1339 r[ 0 ] = m[ 0 ];
1340 r[ 1 ] = m[ 3 ];
1341 r[ 2 ] = m[ 6 ];
1342 r[ 3 ] = m[ 1 ];
1343 r[ 4 ] = m[ 4 ];
1344 r[ 5 ] = m[ 7 ];
1345 r[ 6 ] = m[ 2 ];
1346 r[ 7 ] = m[ 5 ];
1347 r[ 8 ] = m[ 8 ];
1348
1349 return this;
1350
1351 }
1352
1353 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {
1354
1355 const c = Math.cos( rotation );
1356 const s = Math.sin( rotation );
1357
1358 this.set(
1359 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
1360 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
1361 0, 0, 1
1362 );
1363
1364 return this;
1365
1366 }
1367
1368 //
1369
1370 scale( sx, sy ) {
1371
1372 this.premultiply( _m3.makeScale( sx, sy ) );
1373
1374 return this;
1375
1376 }
1377
1378 rotate( theta ) {
1379
1380 this.premultiply( _m3.makeRotation( - theta ) );
1381
1382 return this;
1383
1384 }
1385
1386 translate( tx, ty ) {
1387
1388 this.premultiply( _m3.makeTranslation( tx, ty ) );
1389
1390 return this;
1391
1392 }
1393
1394 // for 2D Transforms
1395
1396 makeTranslation( x, y ) {
1397
1398 if ( x.isVector2 ) {
1399
1400 this.set(
1401
1402 1, 0, x.x,
1403 0, 1, x.y,
1404 0, 0, 1
1405
1406 );
1407
1408 } else {
1409
1410 this.set(
1411
1412 1, 0, x,
1413 0, 1, y,
1414 0, 0, 1
1415
1416 );
1417
1418 }
1419
1420 return this;
1421
1422 }
1423
1424 makeRotation( theta ) {
1425
1426 // counterclockwise
1427
1428 const c = Math.cos( theta );
1429 const s = Math.sin( theta );
1430
1431 this.set(
1432
1433 c, - s, 0,
1434 s, c, 0,
1435 0, 0, 1
1436
1437 );
1438
1439 return this;
1440
1441 }
1442
1443 makeScale( x, y ) {
1444
1445 this.set(
1446
1447 x, 0, 0,
1448 0, y, 0,
1449 0, 0, 1
1450
1451 );
1452
1453 return this;
1454
1455 }
1456
1457 //
1458
1459 equals( matrix ) {
1460
1461 const te = this.elements;
1462 const me = matrix.elements;
1463
1464 for ( let i = 0; i < 9; i ++ ) {
1465
1466 if ( te[ i ] !== me[ i ] ) return false;
1467
1468 }
1469
1470 return true;
1471
1472 }
1473
1474 fromArray( array, offset = 0 ) {
1475
1476 for ( let i = 0; i < 9; i ++ ) {
1477
1478 this.elements[ i ] = array[ i + offset ];
1479
1480 }
1481
1482 return this;
1483
1484 }
1485
1486 toArray( array = [], offset = 0 ) {
1487
1488 const te = this.elements;
1489
1490 array[ offset ] = te[ 0 ];
1491 array[ offset + 1 ] = te[ 1 ];
1492 array[ offset + 2 ] = te[ 2 ];
1493
1494 array[ offset + 3 ] = te[ 3 ];
1495 array[ offset + 4 ] = te[ 4 ];
1496 array[ offset + 5 ] = te[ 5 ];
1497
1498 array[ offset + 6 ] = te[ 6 ];
1499 array[ offset + 7 ] = te[ 7 ];
1500 array[ offset + 8 ] = te[ 8 ];
1501
1502 return array;
1503
1504 }
1505
1506 clone() {
1507
1508 return new this.constructor().fromArray( this.elements );
1509
1510 }
1511
1512 }
1513
1514 const _m3 = /*@__PURE__*/ new Matrix3();
1515
1516 function arrayNeedsUint32( array ) {
1517
1518 // assumes larger values usually on last
1519
1520 for ( let i = array.length - 1; i >= 0; -- i ) {
1521
1522 if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
1523
1524 }
1525
1526 return false;
1527
1528 }
1529
1530 const TYPED_ARRAYS = {
1540 };
1541
1542 function getTypedArray( type, buffer ) {
1543
1544 return new TYPED_ARRAYS[ type ]( buffer );
1545
1546 }
1547
1548 function createElementNS( name ) {
1549
1550 return document.createElementNS( 'http://www.w3.org/1999/xhtml', name );
1551
1552 }
1553
1554 function createCanvasElement() {
1555
1556 const canvas = createElementNS( 'canvas' );
1557 canvas.style.display = 'block';
1558 return canvas;
1559
1560 }
1561
1562 const _cache = {};
1563
1564 function warnOnce( message ) {
1565
1566 if ( message in _cache ) return;
1567
1568 _cache[ message ] = true;
1569
1570 console.warn( message );
1571
1572 }
1573
1586 const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set(
1587 0.8224621, 0.177538, 0.0,
1588 0.0331941, 0.9668058, 0.0,
1589 0.0170827, 0.0723974, 0.9105199,
1590 );
1591
1592 const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set(
1593 1.2249401, - 0.2249404, 0.0,
1594 - 0.0420569, 1.0420571, 0.0,
1595 - 0.0196376, - 0.0786361, 1.0982735
1596 );
1597
1602 const COLOR_SPACES = {
1606 toReference: ( color ) => color,
1607 fromReference: ( color ) => color,
1608 },
1609 [ SRGBColorSpace ]: {
1612 toReference: ( color ) => color.convertSRGBToLinear(),
1613 fromReference: ( color ) => color.convertLinearToSRGB(),
1614 },
1620 },
1621 [ DisplayP3ColorSpace ]: {
1624 toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),
1625 fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(),
1626 },
1627 };
1628
1630
1631 const ColorManagement = {
1632
1633 enabled: true,
1634
1636
1637 get workingColorSpace() {
1638
1639 return this._workingColorSpace;
1640
1641 },
1642
1644
1646
1647 throw new Error( `Unsupported working color space, "${ colorSpace }".` );
1648
1649 }
1650
1652
1653 },
1654
1656
1657 if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {
1658
1659 return color;
1660
1661 }
1662
1663 const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference;
1664 const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference;
1665
1667
1668 },
1669
1671
1672 return this.convert( color, this._workingColorSpace, targetColorSpace );
1673
1674 },
1675
1677
1678 return this.convert( color, sourceColorSpace, this._workingColorSpace );
1679
1680 },
1681
1682 getPrimaries: function ( colorSpace ) {
1683
1684 return COLOR_SPACES[ colorSpace ].primaries;
1685
1686 },
1687
1688 getTransfer: function ( colorSpace ) {
1689
1690 if ( colorSpace === NoColorSpace ) return LinearTransfer;
1691
1692 return COLOR_SPACES[ colorSpace ].transfer;
1693
1694 },
1695
1696 };
1697
1698
1699 function SRGBToLinear( c ) {
1700
1701 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );
1702
1703 }
1704
1705 function LinearToSRGB( c ) {
1706
1707 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;
1708
1709 }
1710
1711 let _canvas;
1712
1713 class ImageUtils {
1714
1715 static getDataURL( image ) {
1716
1717 if ( /^data:/i.test( image.src ) ) {
1718
1719 return image.src;
1720
1721 }
1722
1723 if ( typeof HTMLCanvasElement === 'undefined' ) {
1724
1725 return image.src;
1726
1727 }
1728
1729 let canvas;
1730
1732
1733 canvas = image;
1734
1735 } else {
1736
1737 if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );
1738
1739 _canvas.width = image.width;
1740 _canvas.height = image.height;
1741
1742 const context = _canvas.getContext( '2d' );
1743
1744 if ( image instanceof ImageData ) {
1745
1746 context.putImageData( image, 0, 0 );
1747
1748 } else {
1749
1750 context.drawImage( image, 0, 0, image.width, image.height );
1751
1752 }
1753
1754 canvas = _canvas;
1755
1756 }
1757
1758 if ( canvas.width > 2048 || canvas.height > 2048 ) {
1759
1760 console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );
1761
1762 return canvas.toDataURL( 'image/jpeg', 0.6 );
1763
1764 } else {
1765
1766 return canvas.toDataURL( 'image/png' );
1767
1768 }
1769
1770 }
1771
1772 static sRGBToLinear( image ) {
1773
1774 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1776 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1777
1778 const canvas = createElementNS( 'canvas' );
1779
1780 canvas.width = image.width;
1781 canvas.height = image.height;
1782
1783 const context = canvas.getContext( '2d' );
1784 context.drawImage( image, 0, 0, image.width, image.height );
1785
1786 const imageData = context.getImageData( 0, 0, image.width, image.height );
1787 const data = imageData.data;
1788
1789 for ( let i = 0; i < data.length; i ++ ) {
1790
1791 data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;
1792
1793 }
1794
1795 context.putImageData( imageData, 0, 0 );
1796
1797 return canvas;
1798
1799 } else if ( image.data ) {
1800
1801 const data = image.data.slice( 0 );
1802
1803 for ( let i = 0; i < data.length; i ++ ) {
1804
1806
1807 data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );
1808
1809 } else {
1810
1811 // assuming float
1812
1813 data[ i ] = SRGBToLinear( data[ i ] );
1814
1815 }
1816
1817 }
1818
1819 return {
1820 data: data,
1821 width: image.width,
1822 height: image.height
1823 };
1824
1825 } else {
1826
1827 console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );
1828 return image;
1829
1830 }
1831
1832 }
1833
1834 }
1835
1836 let _sourceId = 0;
1837
1838 class Source {
1839
1840 constructor( data = null ) {
1841
1842 this.isSource = true;
1843
1844 Object.defineProperty( this, 'id', { value: _sourceId ++ } );
1845
1846 this.uuid = generateUUID();
1847
1848 this.data = data;
1849
1850 this.version = 0;
1851
1852 }
1853
1854 set needsUpdate( value ) {
1855
1856 if ( value === true ) this.version ++;
1857
1858 }
1859
1860 toJSON( meta ) {
1861
1862 const isRootObject = ( meta === undefined || typeof meta === 'string' );
1863
1864 if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) {
1865
1866 return meta.images[ this.uuid ];
1867
1868 }
1869
1870 const output = {
1871 uuid: this.uuid,
1872 url: ''
1873 };
1874
1875 const data = this.data;
1876
1877 if ( data !== null ) {
1878
1879 let url;
1880
1881 if ( Array.isArray( data ) ) {
1882
1883 // cube texture
1884
1885 url = [];
1886
1887 for ( let i = 0, l = data.length; i < l; i ++ ) {
1888
1889 if ( data[ i ].isDataTexture ) {
1890
1891 url.push( serializeImage( data[ i ].image ) );
1892
1893 } else {
1894
1895 url.push( serializeImage( data[ i ] ) );
1896
1897 }
1898
1899 }
1900
1901 } else {
1902
1903 // texture
1904
1905 url = serializeImage( data );
1906
1907 }
1908
1909 output.url = url;
1910
1911 }
1912
1913 if ( ! isRootObject ) {
1914
1915 meta.images[ this.uuid ] = output;
1916
1917 }
1918
1919 return output;
1920
1921 }
1922
1923 }
1924
1925 function serializeImage( image ) {
1926
1927 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
1929 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
1930
1931 // default images
1932
1933 return ImageUtils.getDataURL( image );
1934
1935 } else {
1936
1937 if ( image.data ) {
1938
1939 // images of DataTexture
1940
1941 return {
1942 data: Array.from( image.data ),
1943 width: image.width,
1944 height: image.height,
1945 type: image.data.constructor.name
1946 };
1947
1948 } else {
1949
1950 console.warn( 'THREE.Texture: Unable to serialize Texture.' );
1951 return {};
1952
1953 }
1954
1955 }
1956
1957 }
1958
1959 let _textureId = 0;
1960
1961 class Texture extends EventDispatcher {
1962
1964
1965 super();
1966
1967 this.isTexture = true;
1968
1969 Object.defineProperty( this, 'id', { value: _textureId ++ } );
1970
1971 this.uuid = generateUUID();
1972
1973 this.name = '';
1974
1975 this.source = new Source( image );
1976 this.mipmaps = [];
1977
1978 this.mapping = mapping;
1979 this.channel = 0;
1980
1981 this.wrapS = wrapS;
1982 this.wrapT = wrapT;
1983
1984 this.magFilter = magFilter;
1985 this.minFilter = minFilter;
1986
1987 this.anisotropy = anisotropy;
1988
1989 this.format = format;
1990 this.internalFormat = null;
1991 this.type = type;
1992
1993 this.offset = new Vector2( 0, 0 );
1994 this.repeat = new Vector2( 1, 1 );
1995 this.center = new Vector2( 0, 0 );
1996 this.rotation = 0;
1997
1998 this.matrixAutoUpdate = true;
1999 this.matrix = new Matrix3();
2000
2001 this.generateMipmaps = true;
2002 this.premultiplyAlpha = false;
2003 this.flipY = true;
2004 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
2005
2006 if ( typeof colorSpace === 'string' ) {
2007
2008 this.colorSpace = colorSpace;
2009
2010 } else { // @deprecated, r152
2011
2012 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2014
2015 }
2016
2017
2018 this.userData = {};
2019
2020 this.version = 0;
2021 this.onUpdate = null;
2022
2023 this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not
2024 this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures)
2025
2026 }
2027
2028 get image() {
2029
2030 return this.source.data;
2031
2032 }
2033
2034 set image( value = null ) {
2035
2036 this.source.data = value;
2037
2038 }
2039
2040 updateMatrix() {
2041
2042 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
2043
2044 }
2045
2046 clone() {
2047
2048 return new this.constructor().copy( this );
2049
2050 }
2051
2052 copy( source ) {
2053
2054 this.name = source.name;
2055
2056 this.source = source.source;
2057 this.mipmaps = source.mipmaps.slice( 0 );
2058
2059 this.mapping = source.mapping;
2060 this.channel = source.channel;
2061
2062 this.wrapS = source.wrapS;
2063 this.wrapT = source.wrapT;
2064
2065 this.magFilter = source.magFilter;
2066 this.minFilter = source.minFilter;
2067
2068 this.anisotropy = source.anisotropy;
2069
2070 this.format = source.format;
2071 this.internalFormat = source.internalFormat;
2072 this.type = source.type;
2073
2074 this.offset.copy( source.offset );
2075 this.repeat.copy( source.repeat );
2076 this.center.copy( source.center );
2077 this.rotation = source.rotation;
2078
2079 this.matrixAutoUpdate = source.matrixAutoUpdate;
2080 this.matrix.copy( source.matrix );
2081
2082 this.generateMipmaps = source.generateMipmaps;
2083 this.premultiplyAlpha = source.premultiplyAlpha;
2084 this.flipY = source.flipY;
2085 this.unpackAlignment = source.unpackAlignment;
2086 this.colorSpace = source.colorSpace;
2087
2088 this.userData = JSON.parse( JSON.stringify( source.userData ) );
2089
2090 this.needsUpdate = true;
2091
2092 return this;
2093
2094 }
2095
2096 toJSON( meta ) {
2097
2098 const isRootObject = ( meta === undefined || typeof meta === 'string' );
2099
2100 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
2101
2102 return meta.textures[ this.uuid ];
2103
2104 }
2105
2106 const output = {
2107
2108 metadata: {
2109 version: 4.6,
2110 type: 'Texture',
2111 generator: 'Texture.toJSON'
2112 },
2113
2114 uuid: this.uuid,
2115 name: this.name,
2116
2117 image: this.source.toJSON( meta ).uuid,
2118
2119 mapping: this.mapping,
2120 channel: this.channel,
2121
2122 repeat: [ this.repeat.x, this.repeat.y ],
2123 offset: [ this.offset.x, this.offset.y ],
2124 center: [ this.center.x, this.center.y ],
2125 rotation: this.rotation,
2126
2127 wrap: [ this.wrapS, this.wrapT ],
2128
2129 format: this.format,
2131 type: this.type,
2132 colorSpace: this.colorSpace,
2133
2134 minFilter: this.minFilter,
2135 magFilter: this.magFilter,
2136 anisotropy: this.anisotropy,
2137
2138 flipY: this.flipY,
2139
2143
2144 };
2145
2146 if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;
2147
2148 if ( ! isRootObject ) {
2149
2150 meta.textures[ this.uuid ] = output;
2151
2152 }
2153
2154 return output;
2155
2156 }
2157
2158 dispose() {
2159
2160 this.dispatchEvent( { type: 'dispose' } );
2161
2162 }
2163
2164 transformUv( uv ) {
2165
2166 if ( this.mapping !== UVMapping ) return uv;
2167
2168 uv.applyMatrix3( this.matrix );
2169
2170 if ( uv.x < 0 || uv.x > 1 ) {
2171
2172 switch ( this.wrapS ) {
2173
2174 case RepeatWrapping:
2175
2176 uv.x = uv.x - Math.floor( uv.x );
2177 break;
2178
2180
2181 uv.x = uv.x < 0 ? 0 : 1;
2182 break;
2183
2185
2186 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
2187
2188 uv.x = Math.ceil( uv.x ) - uv.x;
2189
2190 } else {
2191
2192 uv.x = uv.x - Math.floor( uv.x );
2193
2194 }
2195
2196 break;
2197
2198 }
2199
2200 }
2201
2202 if ( uv.y < 0 || uv.y > 1 ) {
2203
2204 switch ( this.wrapT ) {
2205
2206 case RepeatWrapping:
2207
2208 uv.y = uv.y - Math.floor( uv.y );
2209 break;
2210
2212
2213 uv.y = uv.y < 0 ? 0 : 1;
2214 break;
2215
2217
2218 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
2219
2220 uv.y = Math.ceil( uv.y ) - uv.y;
2221
2222 } else {
2223
2224 uv.y = uv.y - Math.floor( uv.y );
2225
2226 }
2227
2228 break;
2229
2230 }
2231
2232 }
2233
2234 if ( this.flipY ) {
2235
2236 uv.y = 1 - uv.y;
2237
2238 }
2239
2240 return uv;
2241
2242 }
2243
2244 set needsUpdate( value ) {
2245
2246 if ( value === true ) {
2247
2248 this.version ++;
2249 this.source.needsUpdate = true;
2250
2251 }
2252
2253 }
2254
2255 get encoding() { // @deprecated, r152
2256
2257 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2259
2260 }
2261
2262 set encoding( encoding ) { // @deprecated, r152
2263
2264 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' );
2266
2267 }
2268
2269 }
2270
2271 Texture.DEFAULT_IMAGE = null;
2272 Texture.DEFAULT_MAPPING = UVMapping;
2273 Texture.DEFAULT_ANISOTROPY = 1;
2274
2275 class Vector4 {
2276
2277 constructor( x = 0, y = 0, z = 0, w = 1 ) {
2278
2279 Vector4.prototype.isVector4 = true;
2280
2281 this.x = x;
2282 this.y = y;
2283 this.z = z;
2284 this.w = w;
2285
2286 }
2287
2288 get width() {
2289
2290 return this.z;
2291
2292 }
2293
2294 set width( value ) {
2295
2296 this.z = value;
2297
2298 }
2299
2300 get height() {
2301
2302 return this.w;
2303
2304 }
2305
2306 set height( value ) {
2307
2308 this.w = value;
2309
2310 }
2311
2312 set( x, y, z, w ) {
2313
2314 this.x = x;
2315 this.y = y;
2316 this.z = z;
2317 this.w = w;
2318
2319 return this;
2320
2321 }
2322
2323 setScalar( scalar ) {
2324
2325 this.x = scalar;
2326 this.y = scalar;
2327 this.z = scalar;
2328 this.w = scalar;
2329
2330 return this;
2331
2332 }
2333
2334 setX( x ) {
2335
2336 this.x = x;
2337
2338 return this;
2339
2340 }
2341
2342 setY( y ) {
2343
2344 this.y = y;
2345
2346 return this;
2347
2348 }
2349
2350 setZ( z ) {
2351
2352 this.z = z;
2353
2354 return this;
2355
2356 }
2357
2358 setW( w ) {
2359
2360 this.w = w;
2361
2362 return this;
2363
2364 }
2365
2367
2368 switch ( index ) {
2369
2370 case 0: this.x = value; break;
2371 case 1: this.y = value; break;
2372 case 2: this.z = value; break;
2373 case 3: this.w = value; break;
2374 default: throw new Error( 'index is out of range: ' + index );
2375
2376 }
2377
2378 return this;
2379
2380 }
2381
2382 getComponent( index ) {
2383
2384 switch ( index ) {
2385
2386 case 0: return this.x;
2387 case 1: return this.y;
2388 case 2: return this.z;
2389 case 3: return this.w;
2390 default: throw new Error( 'index is out of range: ' + index );
2391
2392 }
2393
2394 }
2395
2396 clone() {
2397
2398 return new this.constructor( this.x, this.y, this.z, this.w );
2399
2400 }
2401
2402 copy( v ) {
2403
2404 this.x = v.x;
2405 this.y = v.y;
2406 this.z = v.z;
2407 this.w = ( v.w !== undefined ) ? v.w : 1;
2408
2409 return this;
2410
2411 }
2412
2413 add( v ) {
2414
2415 this.x += v.x;
2416 this.y += v.y;
2417 this.z += v.z;
2418 this.w += v.w;
2419
2420 return this;
2421
2422 }
2423
2424 addScalar( s ) {
2425
2426 this.x += s;
2427 this.y += s;
2428 this.z += s;
2429 this.w += s;
2430
2431 return this;
2432
2433 }
2434
2435 addVectors( a, b ) {
2436
2437 this.x = a.x + b.x;
2438 this.y = a.y + b.y;
2439 this.z = a.z + b.z;
2440 this.w = a.w + b.w;
2441
2442 return this;
2443
2444 }
2445
2446 addScaledVector( v, s ) {
2447
2448 this.x += v.x * s;
2449 this.y += v.y * s;
2450 this.z += v.z * s;
2451 this.w += v.w * s;
2452
2453 return this;
2454
2455 }
2456
2457 sub( v ) {
2458
2459 this.x -= v.x;
2460 this.y -= v.y;
2461 this.z -= v.z;
2462 this.w -= v.w;
2463
2464 return this;
2465
2466 }
2467
2468 subScalar( s ) {
2469
2470 this.x -= s;
2471 this.y -= s;
2472 this.z -= s;
2473 this.w -= s;
2474
2475 return this;
2476
2477 }
2478
2479 subVectors( a, b ) {
2480
2481 this.x = a.x - b.x;
2482 this.y = a.y - b.y;
2483 this.z = a.z - b.z;
2484 this.w = a.w - b.w;
2485
2486 return this;
2487
2488 }
2489
2490 multiply( v ) {
2491
2492 this.x *= v.x;
2493 this.y *= v.y;
2494 this.z *= v.z;
2495 this.w *= v.w;
2496
2497 return this;
2498
2499 }
2500
2502
2503 this.x *= scalar;
2504 this.y *= scalar;
2505 this.z *= scalar;
2506 this.w *= scalar;
2507
2508 return this;
2509
2510 }
2511
2512 applyMatrix4( m ) {
2513
2514 const x = this.x, y = this.y, z = this.z, w = this.w;
2515 const e = m.elements;
2516
2517 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
2518 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
2519 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
2520 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
2521
2522 return this;
2523
2524 }
2525
2526 divideScalar( scalar ) {
2527
2528 return this.multiplyScalar( 1 / scalar );
2529
2530 }
2531
2533
2534 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
2535
2536 // q is assumed to be normalized
2537
2538 this.w = 2 * Math.acos( q.w );
2539
2540 const s = Math.sqrt( 1 - q.w * q.w );
2541
2542 if ( s < 0.0001 ) {
2543
2544 this.x = 1;
2545 this.y = 0;
2546 this.z = 0;
2547
2548 } else {
2549
2550 this.x = q.x / s;
2551 this.y = q.y / s;
2552 this.z = q.z / s;
2553
2554 }
2555
2556 return this;
2557
2558 }
2559
2561
2562 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
2563
2564 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
2565
2566 let angle, x, y, z; // variables for result
2567 const epsilon = 0.01, // margin to allow for rounding errors
2568 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
2569
2570 te = m.elements,
2571
2572 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
2573 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
2574 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
2575
2576 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
2577 ( Math.abs( m13 - m31 ) < epsilon ) &&
2578 ( Math.abs( m23 - m32 ) < epsilon ) ) {
2579
2580 // singularity found
2581 // first check for identity matrix which must have +1 for all terms
2582 // in leading diagonal and zero in other terms
2583
2584 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
2585 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
2586 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
2587 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
2588
2589 // this singularity is identity matrix so angle = 0
2590
2591 this.set( 1, 0, 0, 0 );
2592
2593 return this; // zero angle, arbitrary axis
2594
2595 }
2596
2597 // otherwise this singularity is angle = 180
2598
2599 angle = Math.PI;
2600
2601 const xx = ( m11 + 1 ) / 2;
2602 const yy = ( m22 + 1 ) / 2;
2603 const zz = ( m33 + 1 ) / 2;
2604 const xy = ( m12 + m21 ) / 4;
2605 const xz = ( m13 + m31 ) / 4;
2606 const yz = ( m23 + m32 ) / 4;
2607
2608 if ( ( xx > yy ) && ( xx > zz ) ) {
2609
2610 // m11 is the largest diagonal term
2611
2612 if ( xx < epsilon ) {
2613
2614 x = 0;
2615 y = 0.707106781;
2616 z = 0.707106781;
2617
2618 } else {
2619
2620 x = Math.sqrt( xx );
2621 y = xy / x;
2622 z = xz / x;
2623
2624 }
2625
2626 } else if ( yy > zz ) {
2627
2628 // m22 is the largest diagonal term
2629
2630 if ( yy < epsilon ) {
2631
2632 x = 0.707106781;
2633 y = 0;
2634 z = 0.707106781;
2635
2636 } else {
2637
2638 y = Math.sqrt( yy );
2639 x = xy / y;
2640 z = yz / y;
2641
2642 }
2643
2644 } else {
2645
2646 // m33 is the largest diagonal term so base result on this
2647
2648 if ( zz < epsilon ) {
2649
2650 x = 0.707106781;
2651 y = 0.707106781;
2652 z = 0;
2653
2654 } else {
2655
2656 z = Math.sqrt( zz );
2657 x = xz / z;
2658 y = yz / z;
2659
2660 }
2661
2662 }
2663
2664 this.set( x, y, z, angle );
2665
2666 return this; // return 180 deg rotation
2667
2668 }
2669
2670 // as we have reached here there are no singularities so we can handle normally
2671
2672 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
2673 ( m13 - m31 ) * ( m13 - m31 ) +
2674 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
2675
2676 if ( Math.abs( s ) < 0.001 ) s = 1;
2677
2678 // prevent divide by zero, should not happen if matrix is orthogonal and should be
2679 // caught by singularity test above, but I've left it in just in case
2680
2681 this.x = ( m32 - m23 ) / s;
2682 this.y = ( m13 - m31 ) / s;
2683 this.z = ( m21 - m12 ) / s;
2684 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
2685
2686 return this;
2687
2688 }
2689
2690 min( v ) {
2691
2692 this.x = Math.min( this.x, v.x );
2693 this.y = Math.min( this.y, v.y );
2694 this.z = Math.min( this.z, v.z );
2695 this.w = Math.min( this.w, v.w );
2696
2697 return this;
2698
2699 }
2700
2701 max( v ) {
2702
2703 this.x = Math.max( this.x, v.x );
2704 this.y = Math.max( this.y, v.y );
2705 this.z = Math.max( this.z, v.z );
2706 this.w = Math.max( this.w, v.w );
2707
2708 return this;
2709
2710 }
2711
2712 clamp( min, max ) {
2713
2714 // assumes min < max, componentwise
2715
2716 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2717 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2718 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
2719 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
2720
2721 return this;
2722
2723 }
2724
2726
2727 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
2728 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
2729 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
2730 this.w = Math.max( minVal, Math.min( maxVal, this.w ) );
2731
2732 return this;
2733
2734 }
2735
2736 clampLength( min, max ) {
2737
2738 const length = this.length();
2739
2740 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
2741
2742 }
2743
2744 floor() {
2745
2746 this.x = Math.floor( this.x );
2747 this.y = Math.floor( this.y );
2748 this.z = Math.floor( this.z );
2749 this.w = Math.floor( this.w );
2750
2751 return this;
2752
2753 }
2754
2755 ceil() {
2756
2757 this.x = Math.ceil( this.x );
2758 this.y = Math.ceil( this.y );
2759 this.z = Math.ceil( this.z );
2760 this.w = Math.ceil( this.w );
2761
2762 return this;
2763
2764 }
2765
2766 round() {
2767
2768 this.x = Math.round( this.x );
2769 this.y = Math.round( this.y );
2770 this.z = Math.round( this.z );
2771 this.w = Math.round( this.w );
2772
2773 return this;
2774
2775 }
2776
2777 roundToZero() {
2778
2779 this.x = Math.trunc( this.x );
2780 this.y = Math.trunc( this.y );
2781 this.z = Math.trunc( this.z );
2782 this.w = Math.trunc( this.w );
2783
2784 return this;
2785
2786 }
2787
2788 negate() {
2789
2790 this.x = - this.x;
2791 this.y = - this.y;
2792 this.z = - this.z;
2793 this.w = - this.w;
2794
2795 return this;
2796
2797 }
2798
2799 dot( v ) {
2800
2801 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
2802
2803 }
2804
2805 lengthSq() {
2806
2807 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
2808
2809 }
2810
2811 length() {
2812
2813 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
2814
2815 }
2816
2817 manhattanLength() {
2818
2819 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
2820
2821 }
2822
2823 normalize() {
2824
2825 return this.divideScalar( this.length() || 1 );
2826
2827 }
2828
2829 setLength( length ) {
2830
2831 return this.normalize().multiplyScalar( length );
2832
2833 }
2834
2835 lerp( v, alpha ) {
2836
2837 this.x += ( v.x - this.x ) * alpha;
2838 this.y += ( v.y - this.y ) * alpha;
2839 this.z += ( v.z - this.z ) * alpha;
2840 this.w += ( v.w - this.w ) * alpha;
2841
2842 return this;
2843
2844 }
2845
2846 lerpVectors( v1, v2, alpha ) {
2847
2848 this.x = v1.x + ( v2.x - v1.x ) * alpha;
2849 this.y = v1.y + ( v2.y - v1.y ) * alpha;
2850 this.z = v1.z + ( v2.z - v1.z ) * alpha;
2851 this.w = v1.w + ( v2.w - v1.w ) * alpha;
2852
2853 return this;
2854
2855 }
2856
2857 equals( v ) {
2858
2859 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
2860
2861 }
2862
2863 fromArray( array, offset = 0 ) {
2864
2865 this.x = array[ offset ];
2866 this.y = array[ offset + 1 ];
2867 this.z = array[ offset + 2 ];
2868 this.w = array[ offset + 3 ];
2869
2870 return this;
2871
2872 }
2873
2874 toArray( array = [], offset = 0 ) {
2875
2876 array[ offset ] = this.x;
2877 array[ offset + 1 ] = this.y;
2878 array[ offset + 2 ] = this.z;
2879 array[ offset + 3 ] = this.w;
2880
2881 return array;
2882
2883 }
2884
2886
2887 this.x = attribute.getX( index );
2888 this.y = attribute.getY( index );
2889 this.z = attribute.getZ( index );
2890 this.w = attribute.getW( index );
2891
2892 return this;
2893
2894 }
2895
2896 random() {
2897
2898 this.x = Math.random();
2899 this.y = Math.random();
2900 this.z = Math.random();
2901 this.w = Math.random();
2902
2903 return this;
2904
2905 }
2906
2907 *[ Symbol.iterator ]() {
2908
2909 yield this.x;
2910 yield this.y;
2911 yield this.z;
2912 yield this.w;
2913
2914 }
2915
2916 }
2917
2918 /*
2919 In options, we can specify:
2920 * Texture parameters for an auto-generated target texture
2921 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
2922 */
2923 class RenderTarget extends EventDispatcher {
2924
2925 constructor( width = 1, height = 1, options = {} ) {
2926
2927 super();
2928
2929 this.isRenderTarget = true;
2930
2931 this.width = width;
2932 this.height = height;
2933 this.depth = 1;
2934
2935 this.scissor = new Vector4( 0, 0, width, height );
2936 this.scissorTest = false;
2937
2938 this.viewport = new Vector4( 0, 0, width, height );
2939
2940 const image = { width: width, height: height, depth: 1 };
2941
2942 if ( options.encoding !== undefined ) {
2943
2944 // @deprecated, r152
2945 warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' );
2946 options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
2947
2948 }
2949
2950 options = Object.assign( {
2951 generateMipmaps: false,
2952 internalFormat: null,
2954 depthBuffer: true,
2955 stencilBuffer: false,
2956 depthTexture: null,
2957 samples: 0
2958 }, options );
2959
2960 this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
2961 this.texture.isRenderTargetTexture = true;
2962
2963 this.texture.flipY = false;
2964 this.texture.generateMipmaps = options.generateMipmaps;
2965 this.texture.internalFormat = options.internalFormat;
2966
2967 this.depthBuffer = options.depthBuffer;
2968 this.stencilBuffer = options.stencilBuffer;
2969
2970 this.depthTexture = options.depthTexture;
2971
2972 this.samples = options.samples;
2973
2974 }
2975
2976 setSize( width, height, depth = 1 ) {
2977
2978 if ( this.width !== width || this.height !== height || this.depth !== depth ) {
2979
2980 this.width = width;
2981 this.height = height;
2982 this.depth = depth;
2983
2984 this.texture.image.width = width;
2985 this.texture.image.height = height;
2986 this.texture.image.depth = depth;
2987
2988 this.dispose();
2989
2990 }
2991
2992 this.viewport.set( 0, 0, width, height );
2993 this.scissor.set( 0, 0, width, height );
2994
2995 }
2996
2997 clone() {
2998
2999 return new this.constructor().copy( this );
3000
3001 }
3002
3003 copy( source ) {
3004
3005 this.width = source.width;
3006 this.height = source.height;
3007 this.depth = source.depth;
3008
3009 this.scissor.copy( source.scissor );
3010 this.scissorTest = source.scissorTest;
3011
3012 this.viewport.copy( source.viewport );
3013
3014 this.texture = source.texture.clone();
3015 this.texture.isRenderTargetTexture = true;
3016
3017 // ensure image object is not shared, see #20328
3018
3019 const image = Object.assign( {}, source.texture.image );
3020 this.texture.source = new Source( image );
3021
3022 this.depthBuffer = source.depthBuffer;
3023 this.stencilBuffer = source.stencilBuffer;
3024
3025 if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
3026
3027 this.samples = source.samples;
3028
3029 return this;
3030
3031 }
3032
3033 dispose() {
3034
3035 this.dispatchEvent( { type: 'dispose' } );
3036
3037 }
3038
3039 }
3040
3041 class WebGLRenderTarget extends RenderTarget {
3042
3043 constructor( width = 1, height = 1, options = {} ) {
3044
3046
3047 this.isWebGLRenderTarget = true;
3048
3049 }
3050
3051 }
3052
3053 class DataArrayTexture extends Texture {
3054
3055 constructor( data = null, width = 1, height = 1, depth = 1 ) {
3056
3057 super( null );
3058
3059 this.isDataArrayTexture = true;
3060
3061 this.image = { data, width, height, depth };
3062
3063 this.magFilter = NearestFilter;
3064 this.minFilter = NearestFilter;
3065
3067
3068 this.generateMipmaps = false;
3069 this.flipY = false;
3070 this.unpackAlignment = 1;
3071
3072 }
3073
3074 }
3075
3077
3078 constructor( width = 1, height = 1, depth = 1, options = {} ) {
3079
3081
3082 this.isWebGLArrayRenderTarget = true;
3083
3084 this.depth = depth;
3085
3086 this.texture = new DataArrayTexture( null, width, height, depth );
3087
3088 this.texture.isRenderTargetTexture = true;
3089
3090 }
3091
3092 }
3093
3094 class Data3DTexture extends Texture {
3095
3096 constructor( data = null, width = 1, height = 1, depth = 1 ) {
3097
3098 // We're going to add .setXXX() methods for setting properties later.
3099 // Users can still set in DataTexture3D directly.
3100 //
3101 // const texture = new THREE.DataTexture3D( data, width, height, depth );
3102 // texture.anisotropy = 16;
3103 //
3104 // See #14839
3105
3106 super( null );
3107
3108 this.isData3DTexture = true;
3109
3110 this.image = { data, width, height, depth };
3111
3112 this.magFilter = NearestFilter;
3113 this.minFilter = NearestFilter;
3114
3116
3117 this.generateMipmaps = false;
3118 this.flipY = false;
3119 this.unpackAlignment = 1;
3120
3121 }
3122
3123 }
3124
3126
3127 constructor( width = 1, height = 1, depth = 1, options = {} ) {
3128
3130
3131 this.isWebGL3DRenderTarget = true;
3132
3133 this.depth = depth;
3134
3135 this.texture = new Data3DTexture( null, width, height, depth );
3136
3137 this.texture.isRenderTargetTexture = true;
3138
3139 }
3140
3141 }
3142
3144
3145 constructor( width = 1, height = 1, count = 1, options = {} ) {
3146
3148
3149 this.isWebGLMultipleRenderTargets = true;
3150
3151 const texture = this.texture;
3152
3153 this.texture = [];
3154
3155 for ( let i = 0; i < count; i ++ ) {
3156
3157 this.texture[ i ] = texture.clone();
3158 this.texture[ i ].isRenderTargetTexture = true;
3159
3160 }
3161
3162 }
3163
3164 setSize( width, height, depth = 1 ) {
3165
3166 if ( this.width !== width || this.height !== height || this.depth !== depth ) {
3167
3168 this.width = width;
3169 this.height = height;
3170 this.depth = depth;
3171
3172 for ( let i = 0, il = this.texture.length; i < il; i ++ ) {
3173
3174 this.texture[ i ].image.width = width;
3175 this.texture[ i ].image.height = height;
3176 this.texture[ i ].image.depth = depth;
3177
3178 }
3179
3180 this.dispose();
3181
3182 }
3183
3184 this.viewport.set( 0, 0, width, height );
3185 this.scissor.set( 0, 0, width, height );
3186
3187 }
3188
3189 copy( source ) {
3190
3191 this.dispose();
3192
3193 this.width = source.width;
3194 this.height = source.height;
3195 this.depth = source.depth;
3196
3197 this.scissor.copy( source.scissor );
3198 this.scissorTest = source.scissorTest;
3199
3200 this.viewport.copy( source.viewport );
3201
3202 this.depthBuffer = source.depthBuffer;
3203 this.stencilBuffer = source.stencilBuffer;
3204
3205 if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
3206
3207 this.texture.length = 0;
3208
3209 for ( let i = 0, il = source.texture.length; i < il; i ++ ) {
3210
3211 this.texture[ i ] = source.texture[ i ].clone();
3212 this.texture[ i ].isRenderTargetTexture = true;
3213
3214 }
3215
3216 return this;
3217
3218 }
3219
3220 }
3221
3222 class Quaternion {
3223
3224 constructor( x = 0, y = 0, z = 0, w = 1 ) {
3225
3226 this.isQuaternion = true;
3227
3228 this._x = x;
3229 this._y = y;
3230 this._z = z;
3231 this._w = w;
3232
3233 }
3234
3236
3237 // fuzz-free, array-based Quaternion SLERP operation
3238
3239 let x0 = src0[ srcOffset0 + 0 ],
3240 y0 = src0[ srcOffset0 + 1 ],
3241 z0 = src0[ srcOffset0 + 2 ],
3242 w0 = src0[ srcOffset0 + 3 ];
3243
3244 const x1 = src1[ srcOffset1 + 0 ],
3245 y1 = src1[ srcOffset1 + 1 ],
3246 z1 = src1[ srcOffset1 + 2 ],
3247 w1 = src1[ srcOffset1 + 3 ];
3248
3249 if ( t === 0 ) {
3250
3251 dst[ dstOffset + 0 ] = x0;
3252 dst[ dstOffset + 1 ] = y0;
3253 dst[ dstOffset + 2 ] = z0;
3254 dst[ dstOffset + 3 ] = w0;
3255 return;
3256
3257 }
3258
3259 if ( t === 1 ) {
3260
3261 dst[ dstOffset + 0 ] = x1;
3262 dst[ dstOffset + 1 ] = y1;
3263 dst[ dstOffset + 2 ] = z1;
3264 dst[ dstOffset + 3 ] = w1;
3265 return;
3266
3267 }
3268
3269 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
3270
3271 let s = 1 - t;
3272 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
3273 dir = ( cos >= 0 ? 1 : - 1 ),
3274 sqrSin = 1 - cos * cos;
3275
3276 // Skip the Slerp for tiny steps to avoid numeric problems:
3277 if ( sqrSin > Number.EPSILON ) {
3278
3279 const sin = Math.sqrt( sqrSin ),
3280 len = Math.atan2( sin, cos * dir );
3281
3282 s = Math.sin( s * len ) / sin;
3283 t = Math.sin( t * len ) / sin;
3284
3285 }
3286
3287 const tDir = t * dir;
3288
3289 x0 = x0 * s + x1 * tDir;
3290 y0 = y0 * s + y1 * tDir;
3291 z0 = z0 * s + z1 * tDir;
3292 w0 = w0 * s + w1 * tDir;
3293
3294 // Normalize in case we just did a lerp:
3295 if ( s === 1 - t ) {
3296
3297 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
3298
3299 x0 *= f;
3300 y0 *= f;
3301 z0 *= f;
3302 w0 *= f;
3303
3304 }
3305
3306 }
3307
3308 dst[ dstOffset ] = x0;
3309 dst[ dstOffset + 1 ] = y0;
3310 dst[ dstOffset + 2 ] = z0;
3311 dst[ dstOffset + 3 ] = w0;
3312
3313 }
3314
3316
3317 const x0 = src0[ srcOffset0 ];
3318 const y0 = src0[ srcOffset0 + 1 ];
3319 const z0 = src0[ srcOffset0 + 2 ];
3320 const w0 = src0[ srcOffset0 + 3 ];
3321
3322 const x1 = src1[ srcOffset1 ];
3323 const y1 = src1[ srcOffset1 + 1 ];
3324 const z1 = src1[ srcOffset1 + 2 ];
3325 const w1 = src1[ srcOffset1 + 3 ];
3326
3327 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
3328 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
3329 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
3330 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
3331
3332 return dst;
3333
3334 }
3335
3336 get x() {
3337
3338 return this._x;
3339
3340 }
3341
3342 set x( value ) {
3343
3344 this._x = value;
3345 this._onChangeCallback();
3346
3347 }
3348
3349 get y() {
3350
3351 return this._y;
3352
3353 }
3354
3355 set y( value ) {
3356
3357 this._y = value;
3358 this._onChangeCallback();
3359
3360 }
3361
3362 get z() {
3363
3364 return this._z;
3365
3366 }
3367
3368 set z( value ) {
3369
3370 this._z = value;
3371 this._onChangeCallback();
3372
3373 }
3374
3375 get w() {
3376
3377 return this._w;
3378
3379 }
3380
3381 set w( value ) {
3382
3383 this._w = value;
3384 this._onChangeCallback();
3385
3386 }
3387
3388 set( x, y, z, w ) {
3389
3390 this._x = x;
3391 this._y = y;
3392 this._z = z;
3393 this._w = w;
3394
3395 this._onChangeCallback();
3396
3397 return this;
3398
3399 }
3400
3401 clone() {
3402
3403 return new this.constructor( this._x, this._y, this._z, this._w );
3404
3405 }
3406
3407 copy( quaternion ) {
3408
3409 this._x = quaternion.x;
3410 this._y = quaternion.y;
3411 this._z = quaternion.z;
3412 this._w = quaternion.w;
3413
3414 this._onChangeCallback();
3415
3416 return this;
3417
3418 }
3419
3420 setFromEuler( euler, update = true ) {
3421
3422 const x = euler._x, y = euler._y, z = euler._z, order = euler._order;
3423
3424 // http://www.mathworks.com/matlabcentral/fileexchange/
3425 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
3426 // content/SpinCalc.m
3427
3428 const cos = Math.cos;
3429 const sin = Math.sin;
3430
3431 const c1 = cos( x / 2 );
3432 const c2 = cos( y / 2 );
3433 const c3 = cos( z / 2 );
3434
3435 const s1 = sin( x / 2 );
3436 const s2 = sin( y / 2 );
3437 const s3 = sin( z / 2 );
3438
3439 switch ( order ) {
3440
3441 case 'XYZ':
3442 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3443 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3444 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3445 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3446 break;
3447
3448 case 'YXZ':
3449 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3450 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3451 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3452 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3453 break;
3454
3455 case 'ZXY':
3456 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3457 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3458 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3459 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3460 break;
3461
3462 case 'ZYX':
3463 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3464 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3465 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3466 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3467 break;
3468
3469 case 'YZX':
3470 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3471 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3472 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3473 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3474 break;
3475
3476 case 'XZY':
3477 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3478 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3479 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3480 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3481 break;
3482
3483 default:
3484 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );
3485
3486 }
3487
3488 if ( update === true ) this._onChangeCallback();
3489
3490 return this;
3491
3492 }
3493
3494 setFromAxisAngle( axis, angle ) {
3495
3496 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
3497
3498 // assumes axis is normalized
3499
3500 const halfAngle = angle / 2, s = Math.sin( halfAngle );
3501
3502 this._x = axis.x * s;
3503 this._y = axis.y * s;
3504 this._z = axis.z * s;
3505 this._w = Math.cos( halfAngle );
3506
3507 this._onChangeCallback();
3508
3509 return this;
3510
3511 }
3512
3514
3515 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
3516
3517 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
3518
3519 const te = m.elements,
3520
3521 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
3522 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
3523 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
3524
3525 trace = m11 + m22 + m33;
3526
3527 if ( trace > 0 ) {
3528
3529 const s = 0.5 / Math.sqrt( trace + 1.0 );
3530
3531 this._w = 0.25 / s;
3532 this._x = ( m32 - m23 ) * s;
3533 this._y = ( m13 - m31 ) * s;
3534 this._z = ( m21 - m12 ) * s;
3535
3536 } else if ( m11 > m22 && m11 > m33 ) {
3537
3538 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
3539
3540 this._w = ( m32 - m23 ) / s;
3541 this._x = 0.25 * s;
3542 this._y = ( m12 + m21 ) / s;
3543 this._z = ( m13 + m31 ) / s;
3544
3545 } else if ( m22 > m33 ) {
3546
3547 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
3548
3549 this._w = ( m13 - m31 ) / s;
3550 this._x = ( m12 + m21 ) / s;
3551 this._y = 0.25 * s;
3552 this._z = ( m23 + m32 ) / s;
3553
3554 } else {
3555
3556 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
3557
3558 this._w = ( m21 - m12 ) / s;
3559 this._x = ( m13 + m31 ) / s;
3560 this._y = ( m23 + m32 ) / s;
3561 this._z = 0.25 * s;
3562
3563 }
3564
3565 this._onChangeCallback();
3566
3567 return this;
3568
3569 }
3570
3572
3573 // assumes direction vectors vFrom and vTo are normalized
3574
3575 let r = vFrom.dot( vTo ) + 1;
3576
3577 if ( r < Number.EPSILON ) {
3578
3579 // vFrom and vTo point in opposite directions
3580
3581 r = 0;
3582
3583 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
3584
3585 this._x = - vFrom.y;
3586 this._y = vFrom.x;
3587 this._z = 0;
3588 this._w = r;
3589
3590 } else {
3591
3592 this._x = 0;
3593 this._y = - vFrom.z;
3594 this._z = vFrom.y;
3595 this._w = r;
3596
3597 }
3598
3599 } else {
3600
3601 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
3602
3603 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
3604 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
3605 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
3606 this._w = r;
3607
3608 }
3609
3610 return this.normalize();
3611
3612 }
3613
3614 angleTo( q ) {
3615
3616 return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) );
3617
3618 }
3619
3620 rotateTowards( q, step ) {
3621
3622 const angle = this.angleTo( q );
3623
3624 if ( angle === 0 ) return this;
3625
3626 const t = Math.min( 1, step / angle );
3627
3628 this.slerp( q, t );
3629
3630 return this;
3631
3632 }
3633
3634 identity() {
3635
3636 return this.set( 0, 0, 0, 1 );
3637
3638 }
3639
3640 invert() {
3641
3642 // quaternion is assumed to have unit length
3643
3644 return this.conjugate();
3645
3646 }
3647
3648 conjugate() {
3649
3650 this._x *= - 1;
3651 this._y *= - 1;
3652 this._z *= - 1;
3653
3654 this._onChangeCallback();
3655
3656 return this;
3657
3658 }
3659
3660 dot( v ) {
3661
3662 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
3663
3664 }
3665
3666 lengthSq() {
3667
3668 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
3669
3670 }
3671
3672 length() {
3673
3674 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
3675
3676 }
3677
3678 normalize() {
3679
3680 let l = this.length();
3681
3682 if ( l === 0 ) {
3683
3684 this._x = 0;
3685 this._y = 0;
3686 this._z = 0;
3687 this._w = 1;
3688
3689 } else {
3690
3691 l = 1 / l;
3692
3693 this._x = this._x * l;
3694 this._y = this._y * l;
3695 this._z = this._z * l;
3696 this._w = this._w * l;
3697
3698 }
3699
3700 this._onChangeCallback();
3701
3702 return this;
3703
3704 }
3705
3706 multiply( q ) {
3707
3708 return this.multiplyQuaternions( this, q );
3709
3710 }
3711
3712 premultiply( q ) {
3713
3714 return this.multiplyQuaternions( q, this );
3715
3716 }
3717
3718 multiplyQuaternions( a, b ) {
3719
3720 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
3721
3722 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
3723 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
3724
3725 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
3726 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
3727 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
3728 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
3729
3730 this._onChangeCallback();
3731
3732 return this;
3733
3734 }
3735
3736 slerp( qb, t ) {
3737
3738 if ( t === 0 ) return this;
3739 if ( t === 1 ) return this.copy( qb );
3740
3741 const x = this._x, y = this._y, z = this._z, w = this._w;
3742
3743 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
3744
3745 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
3746
3747 if ( cosHalfTheta < 0 ) {
3748
3749 this._w = - qb._w;
3750 this._x = - qb._x;
3751 this._y = - qb._y;
3752 this._z = - qb._z;
3753
3754 cosHalfTheta = - cosHalfTheta;
3755
3756 } else {
3757
3758 this.copy( qb );
3759
3760 }
3761
3762 if ( cosHalfTheta >= 1.0 ) {
3763
3764 this._w = w;
3765 this._x = x;
3766 this._y = y;
3767 this._z = z;
3768
3769 return this;
3770
3771 }
3772
3773 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
3774
3775 if ( sqrSinHalfTheta <= Number.EPSILON ) {
3776
3777 const s = 1 - t;
3778 this._w = s * w + t * this._w;
3779 this._x = s * x + t * this._x;
3780 this._y = s * y + t * this._y;
3781 this._z = s * z + t * this._z;
3782
3783 this.normalize(); // normalize calls _onChangeCallback()
3784
3785 return this;
3786
3787 }
3788
3789 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta );
3790 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
3791 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
3792 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
3793
3794 this._w = ( w * ratioA + this._w * ratioB );
3795 this._x = ( x * ratioA + this._x * ratioB );
3796 this._y = ( y * ratioA + this._y * ratioB );
3797 this._z = ( z * ratioA + this._z * ratioB );
3798
3799 this._onChangeCallback();
3800
3801 return this;
3802
3803 }
3804
3805 slerpQuaternions( qa, qb, t ) {
3806
3807 return this.copy( qa ).slerp( qb, t );
3808
3809 }
3810
3811 random() {
3812
3813 // Derived from http://planning.cs.uiuc.edu/node198.html
3814 // Note, this source uses w, x, y, z ordering,
3815 // so we swap the order below.
3816
3817 const u1 = Math.random();
3818 const sqrt1u1 = Math.sqrt( 1 - u1 );
3819 const sqrtu1 = Math.sqrt( u1 );
3820
3821 const u2 = 2 * Math.PI * Math.random();
3822
3823 const u3 = 2 * Math.PI * Math.random();
3824
3825 return this.set(
3826 sqrt1u1 * Math.cos( u2 ),
3827 sqrtu1 * Math.sin( u3 ),
3828 sqrtu1 * Math.cos( u3 ),
3829 sqrt1u1 * Math.sin( u2 ),
3830 );
3831
3832 }
3833
3834 equals( quaternion ) {
3835
3836 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
3837
3838 }
3839
3840 fromArray( array, offset = 0 ) {
3841
3842 this._x = array[ offset ];
3843 this._y = array[ offset + 1 ];
3844 this._z = array[ offset + 2 ];
3845 this._w = array[ offset + 3 ];
3846
3847 this._onChangeCallback();
3848
3849 return this;
3850
3851 }
3852
3853 toArray( array = [], offset = 0 ) {
3854
3855 array[ offset ] = this._x;
3856 array[ offset + 1 ] = this._y;
3857 array[ offset + 2 ] = this._z;
3858 array[ offset + 3 ] = this._w;
3859
3860 return array;
3861
3862 }
3863
3865
3866 this._x = attribute.getX( index );
3867 this._y = attribute.getY( index );
3868 this._z = attribute.getZ( index );
3869 this._w = attribute.getW( index );
3870
3871 this._onChangeCallback();
3872
3873 return this;
3874
3875 }
3876
3877 toJSON() {
3878
3879 return this.toArray();
3880
3881 }
3882
3883 _onChange( callback ) {
3884
3886
3887 return this;
3888
3889 }
3890
3892
3893 *[ Symbol.iterator ]() {
3894
3895 yield this._x;
3896 yield this._y;
3897 yield this._z;
3898 yield this._w;
3899
3900 }
3901
3902 }
3903
3904 class Vector3 {
3905
3906 constructor( x = 0, y = 0, z = 0 ) {
3907
3908 Vector3.prototype.isVector3 = true;
3909
3910 this.x = x;
3911 this.y = y;
3912 this.z = z;
3913
3914 }
3915
3916 set( x, y, z ) {
3917
3918 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
3919
3920 this.x = x;
3921 this.y = y;
3922 this.z = z;
3923
3924 return this;
3925
3926 }
3927
3928 setScalar( scalar ) {
3929
3930 this.x = scalar;
3931 this.y = scalar;
3932 this.z = scalar;
3933
3934 return this;
3935
3936 }
3937
3938 setX( x ) {
3939
3940 this.x = x;
3941
3942 return this;
3943
3944 }
3945
3946 setY( y ) {
3947
3948 this.y = y;
3949
3950 return this;
3951
3952 }
3953
3954 setZ( z ) {
3955
3956 this.z = z;
3957
3958 return this;
3959
3960 }
3961
3963
3964 switch ( index ) {
3965
3966 case 0: this.x = value; break;
3967 case 1: this.y = value; break;
3968 case 2: this.z = value; break;
3969 default: throw new Error( 'index is out of range: ' + index );
3970
3971 }
3972
3973 return this;
3974
3975 }
3976
3977 getComponent( index ) {
3978
3979 switch ( index ) {
3980
3981 case 0: return this.x;
3982 case 1: return this.y;
3983 case 2: return this.z;
3984 default: throw new Error( 'index is out of range: ' + index );
3985
3986 }
3987
3988 }
3989
3990 clone() {
3991
3992 return new this.constructor( this.x, this.y, this.z );
3993
3994 }
3995
3996 copy( v ) {
3997
3998 this.x = v.x;
3999 this.y = v.y;
4000 this.z = v.z;
4001
4002 return this;
4003
4004 }
4005
4006 add( v ) {
4007
4008 this.x += v.x;
4009 this.y += v.y;
4010 this.z += v.z;
4011
4012 return this;
4013
4014 }
4015
4016 addScalar( s ) {
4017
4018 this.x += s;
4019 this.y += s;
4020 this.z += s;
4021
4022 return this;
4023
4024 }
4025
4026 addVectors( a, b ) {
4027
4028 this.x = a.x + b.x;
4029 this.y = a.y + b.y;
4030 this.z = a.z + b.z;
4031
4032 return this;
4033
4034 }
4035
4036 addScaledVector( v, s ) {
4037
4038 this.x += v.x * s;
4039 this.y += v.y * s;
4040 this.z += v.z * s;
4041
4042 return this;
4043
4044 }
4045
4046 sub( v ) {
4047
4048 this.x -= v.x;
4049 this.y -= v.y;
4050 this.z -= v.z;
4051
4052 return this;
4053
4054 }
4055
4056 subScalar( s ) {
4057
4058 this.x -= s;
4059 this.y -= s;
4060 this.z -= s;
4061
4062 return this;
4063
4064 }
4065
4066 subVectors( a, b ) {
4067
4068 this.x = a.x - b.x;
4069 this.y = a.y - b.y;
4070 this.z = a.z - b.z;
4071
4072 return this;
4073
4074 }
4075
4076 multiply( v ) {
4077
4078 this.x *= v.x;
4079 this.y *= v.y;
4080 this.z *= v.z;
4081
4082 return this;
4083
4084 }
4085
4087
4088 this.x *= scalar;
4089 this.y *= scalar;
4090 this.z *= scalar;
4091
4092 return this;
4093
4094 }
4095
4096 multiplyVectors( a, b ) {
4097
4098 this.x = a.x * b.x;
4099 this.y = a.y * b.y;
4100 this.z = a.z * b.z;
4101
4102 return this;
4103
4104 }
4105
4106 applyEuler( euler ) {
4107
4108 return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );
4109
4110 }
4111
4112 applyAxisAngle( axis, angle ) {
4113
4114 return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );
4115
4116 }
4117
4118 applyMatrix3( m ) {
4119
4120 const x = this.x, y = this.y, z = this.z;
4121 const e = m.elements;
4122
4123 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
4124 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
4125 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
4126
4127 return this;
4128
4129 }
4130
4131 applyNormalMatrix( m ) {
4132
4133 return this.applyMatrix3( m ).normalize();
4134
4135 }
4136
4137 applyMatrix4( m ) {
4138
4139 const x = this.x, y = this.y, z = this.z;
4140 const e = m.elements;
4141
4142 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
4143
4144 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
4145 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
4146 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
4147
4148 return this;
4149
4150 }
4151
4152 applyQuaternion( q ) {
4153
4154 // quaternion q is assumed to have unit length
4155
4156 const vx = this.x, vy = this.y, vz = this.z;
4157 const qx = q.x, qy = q.y, qz = q.z, qw = q.w;
4158
4159 // t = 2 * cross( q.xyz, v );
4160 const tx = 2 * ( qy * vz - qz * vy );
4161 const ty = 2 * ( qz * vx - qx * vz );
4162 const tz = 2 * ( qx * vy - qy * vx );
4163
4164 // v + q.w * t + cross( q.xyz, t );
4165 this.x = vx + qw * tx + qy * tz - qz * ty;
4166 this.y = vy + qw * ty + qz * tx - qx * tz;
4167 this.z = vz + qw * tz + qx * ty - qy * tx;
4168
4169 return this;
4170
4171 }
4172
4173 project( camera ) {
4174
4175 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
4176
4177 }
4178
4179 unproject( camera ) {
4180
4181 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );
4182
4183 }
4184
4186
4187 // input: THREE.Matrix4 affine matrix
4188 // vector interpreted as a direction
4189
4190 const x = this.x, y = this.y, z = this.z;
4191 const e = m.elements;
4192
4193 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
4194 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
4195 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
4196
4197 return this.normalize();
4198
4199 }
4200
4201 divide( v ) {
4202
4203 this.x /= v.x;
4204 this.y /= v.y;
4205 this.z /= v.z;
4206
4207 return this;
4208
4209 }
4210
4211 divideScalar( scalar ) {
4212
4213 return this.multiplyScalar( 1 / scalar );
4214
4215 }
4216
4217 min( v ) {
4218
4219 this.x = Math.min( this.x, v.x );
4220 this.y = Math.min( this.y, v.y );
4221 this.z = Math.min( this.z, v.z );
4222
4223 return this;
4224
4225 }
4226
4227 max( v ) {
4228
4229 this.x = Math.max( this.x, v.x );
4230 this.y = Math.max( this.y, v.y );
4231 this.z = Math.max( this.z, v.z );
4232
4233 return this;
4234
4235 }
4236
4237 clamp( min, max ) {
4238
4239 // assumes min < max, componentwise
4240
4241 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
4242 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
4243 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
4244
4245 return this;
4246
4247 }
4248
4250
4251 this.x = Math.max( minVal, Math.min( maxVal, this.x ) );
4252 this.y = Math.max( minVal, Math.min( maxVal, this.y ) );
4253 this.z = Math.max( minVal, Math.min( maxVal, this.z ) );
4254
4255 return this;
4256
4257 }
4258
4259 clampLength( min, max ) {
4260
4261 const length = this.length();
4262
4263 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
4264
4265 }
4266
4267 floor() {
4268
4269 this.x = Math.floor( this.x );
4270 this.y = Math.floor( this.y );
4271 this.z = Math.floor( this.z );
4272
4273 return this;
4274
4275 }
4276
4277 ceil() {
4278
4279 this.x = Math.ceil( this.x );
4280 this.y = Math.ceil( this.y );
4281 this.z = Math.ceil( this.z );
4282
4283 return this;
4284
4285 }
4286
4287 round() {
4288
4289 this.x = Math.round( this.x );
4290 this.y = Math.round( this.y );
4291 this.z = Math.round( this.z );
4292
4293 return this;
4294
4295 }
4296
4297 roundToZero() {
4298
4299 this.x = Math.trunc( this.x );
4300 this.y = Math.trunc( this.y );
4301 this.z = Math.trunc( this.z );
4302
4303 return this;
4304
4305 }
4306
4307 negate() {
4308
4309 this.x = - this.x;
4310 this.y = - this.y;
4311 this.z = - this.z;
4312
4313 return this;
4314
4315 }
4316
4317 dot( v ) {
4318
4319 return this.x * v.x + this.y * v.y + this.z * v.z;
4320
4321 }
4322
4323 // TODO lengthSquared?
4324
4325 lengthSq() {
4326
4327 return this.x * this.x + this.y * this.y + this.z * this.z;
4328
4329 }
4330
4331 length() {
4332
4333 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
4334
4335 }
4336
4337 manhattanLength() {
4338
4339 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
4340
4341 }
4342
4343 normalize() {
4344
4345 return this.divideScalar( this.length() || 1 );
4346
4347 }
4348
4349 setLength( length ) {
4350
4351 return this.normalize().multiplyScalar( length );
4352
4353 }
4354
4355 lerp( v, alpha ) {
4356
4357 this.x += ( v.x - this.x ) * alpha;
4358 this.y += ( v.y - this.y ) * alpha;
4359 this.z += ( v.z - this.z ) * alpha;
4360
4361 return this;
4362
4363 }
4364
4365 lerpVectors( v1, v2, alpha ) {
4366
4367 this.x = v1.x + ( v2.x - v1.x ) * alpha;
4368 this.y = v1.y + ( v2.y - v1.y ) * alpha;
4369 this.z = v1.z + ( v2.z - v1.z ) * alpha;
4370
4371 return this;
4372
4373 }
4374
4375 cross( v ) {
4376
4377 return this.crossVectors( this, v );
4378
4379 }
4380
4381 crossVectors( a, b ) {
4382
4383 const ax = a.x, ay = a.y, az = a.z;
4384 const bx = b.x, by = b.y, bz = b.z;
4385
4386 this.x = ay * bz - az * by;
4387 this.y = az * bx - ax * bz;
4388 this.z = ax * by - ay * bx;
4389
4390 return this;
4391
4392 }
4393
4394 projectOnVector( v ) {
4395
4396 const denominator = v.lengthSq();
4397
4398 if ( denominator === 0 ) return this.set( 0, 0, 0 );
4399
4400 const scalar = v.dot( this ) / denominator;
4401
4402 return this.copy( v ).multiplyScalar( scalar );
4403
4404 }
4405
4407
4408 _vector$c.copy( this ).projectOnVector( planeNormal );
4409
4410 return this.sub( _vector$c );
4411
4412 }
4413
4414 reflect( normal ) {
4415
4416 // reflect incident vector off plane orthogonal to normal
4417 // normal is assumed to have unit length
4418
4419 return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
4420
4421 }
4422
4423 angleTo( v ) {
4424
4425 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );
4426
4427 if ( denominator === 0 ) return Math.PI / 2;
4428
4429 const theta = this.dot( v ) / denominator;
4430
4431 // clamp, to handle numerical problems
4432
4433 return Math.acos( clamp( theta, - 1, 1 ) );
4434
4435 }
4436
4437 distanceTo( v ) {
4438
4439 return Math.sqrt( this.distanceToSquared( v ) );
4440
4441 }
4442
4443 distanceToSquared( v ) {
4444
4445 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
4446
4447 return dx * dx + dy * dy + dz * dz;
4448
4449 }
4450
4452
4453 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
4454
4455 }
4456
4457 setFromSpherical( s ) {
4458
4459 return this.setFromSphericalCoords( s.radius, s.phi, s.theta );
4460
4461 }
4462
4464
4465 const sinPhiRadius = Math.sin( phi ) * radius;
4466
4467 this.x = sinPhiRadius * Math.sin( theta );
4468 this.y = Math.cos( phi ) * radius;
4469 this.z = sinPhiRadius * Math.cos( theta );
4470
4471 return this;
4472
4473 }
4474
4476
4477 return this.setFromCylindricalCoords( c.radius, c.theta, c.y );
4478
4479 }
4480
4482
4483 this.x = radius * Math.sin( theta );
4484 this.y = y;
4485 this.z = radius * Math.cos( theta );
4486
4487 return this;
4488
4489 }
4490
4492
4493 const e = m.elements;
4494
4495 this.x = e[ 12 ];
4496 this.y = e[ 13 ];
4497 this.z = e[ 14 ];
4498
4499 return this;
4500
4501 }
4502
4504
4505 const sx = this.setFromMatrixColumn( m, 0 ).length();
4506 const sy = this.setFromMatrixColumn( m, 1 ).length();
4507 const sz = this.setFromMatrixColumn( m, 2 ).length();
4508
4509 this.x = sx;
4510 this.y = sy;
4511 this.z = sz;
4512
4513 return this;
4514
4515 }
4516
4518
4519 return this.fromArray( m.elements, index * 4 );
4520
4521 }
4522
4524
4525 return this.fromArray( m.elements, index * 3 );
4526
4527 }
4528
4529 setFromEuler( e ) {
4530
4531 this.x = e._x;
4532 this.y = e._y;
4533 this.z = e._z;
4534
4535 return this;
4536
4537 }
4538
4539 setFromColor( c ) {
4540
4541 this.x = c.r;
4542 this.y = c.g;
4543 this.z = c.b;
4544
4545 return this;
4546
4547 }
4548
4549 equals( v ) {
4550
4551 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
4552
4553 }
4554
4555 fromArray( array, offset = 0 ) {
4556
4557 this.x = array[ offset ];
4558 this.y = array[ offset + 1 ];
4559 this.z = array[ offset + 2 ];
4560
4561 return this;
4562
4563 }
4564
4565 toArray( array = [], offset = 0 ) {
4566
4567 array[ offset ] = this.x;
4568 array[ offset + 1 ] = this.y;
4569 array[ offset + 2 ] = this.z;
4570
4571 return array;
4572
4573 }
4574
4576
4577 this.x = attribute.getX( index );
4578 this.y = attribute.getY( index );
4579 this.z = attribute.getZ( index );
4580
4581 return this;
4582
4583 }
4584
4585 random() {
4586
4587 this.x = Math.random();
4588 this.y = Math.random();
4589 this.z = Math.random();
4590
4591 return this;
4592
4593 }
4594
4595 randomDirection() {
4596
4597 // Derived from https://mathworld.wolfram.com/SpherePointPicking.html
4598
4599 const u = ( Math.random() - 0.5 ) * 2;
4600 const t = Math.random() * Math.PI * 2;
4601 const f = Math.sqrt( 1 - u ** 2 );
4602
4603 this.x = f * Math.cos( t );
4604 this.y = f * Math.sin( t );
4605 this.z = u;
4606
4607 return this;
4608
4609 }
4610
4611 *[ Symbol.iterator ]() {
4612
4613 yield this.x;
4614 yield this.y;
4615 yield this.z;
4616
4617 }
4618
4619 }
4620
4621 const _vector$c = /*@__PURE__*/ new Vector3();
4622 const _quaternion$4 = /*@__PURE__*/ new Quaternion();
4623
4624 class Box3 {
4625
4626 constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {
4627
4628 this.isBox3 = true;
4629
4630 this.min = min;
4631 this.max = max;
4632
4633 }
4634
4635 set( min, max ) {
4636
4637 this.min.copy( min );
4638 this.max.copy( max );
4639
4640 return this;
4641
4642 }
4643
4644 setFromArray( array ) {
4645
4646 this.makeEmpty();
4647
4648 for ( let i = 0, il = array.length; i < il; i += 3 ) {
4649
4650 this.expandByPoint( _vector$b.fromArray( array, i ) );
4651
4652 }
4653
4654 return this;
4655
4656 }
4657
4659
4660 this.makeEmpty();
4661
4662 for ( let i = 0, il = attribute.count; i < il; i ++ ) {
4663
4664 this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) );
4665
4666 }
4667
4668 return this;
4669
4670 }
4671
4673
4674 this.makeEmpty();
4675
4676 for ( let i = 0, il = points.length; i < il; i ++ ) {
4677
4678 this.expandByPoint( points[ i ] );
4679
4680 }
4681
4682 return this;
4683
4684 }
4685
4687
4688 const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );
4689
4690 this.min.copy( center ).sub( halfSize );
4691 this.max.copy( center ).add( halfSize );
4692
4693 return this;
4694
4695 }
4696
4697 setFromObject( object, precise = false ) {
4698
4699 this.makeEmpty();
4700
4701 return this.expandByObject( object, precise );
4702
4703 }
4704
4705 clone() {
4706
4707 return new this.constructor().copy( this );
4708
4709 }
4710
4711 copy( box ) {
4712
4713 this.min.copy( box.min );
4714 this.max.copy( box.max );
4715
4716 return this;
4717
4718 }
4719
4720 makeEmpty() {
4721
4722 this.min.x = this.min.y = this.min.z = + Infinity;
4723 this.max.x = this.max.y = this.max.z = - Infinity;
4724
4725 return this;
4726
4727 }
4728
4729 isEmpty() {
4730
4731 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
4732
4733 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
4734
4735 }
4736
4737 getCenter( target ) {
4738
4739 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
4740
4741 }
4742
4743 getSize( target ) {
4744
4745 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );
4746
4747 }
4748
4749 expandByPoint( point ) {
4750
4751 this.min.min( point );
4752 this.max.max( point );
4753
4754 return this;
4755
4756 }
4757
4759
4760 this.min.sub( vector );
4761 this.max.add( vector );
4762
4763 return this;
4764
4765 }
4766
4768
4769 this.min.addScalar( - scalar );
4770 this.max.addScalar( scalar );
4771
4772 return this;
4773
4774 }
4775
4776 expandByObject( object, precise = false ) {
4777
4778 // Computes the world-axis-aligned bounding box of an object (including its children),
4779 // accounting for both the object's, and children's, world transforms
4780
4781 object.updateWorldMatrix( false, false );
4782
4783 const geometry = object.geometry;
4784
4785 if ( geometry !== undefined ) {
4786
4787 const positionAttribute = geometry.getAttribute( 'position' );
4788
4789 // precise AABB computation based on vertex data requires at least a position attribute.
4790 // instancing isn't supported so far and uses the normal (conservative) code path.
4791
4792 if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {
4793
4794 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {
4795
4796 if ( object.isMesh === true ) {
4797
4798 object.getVertexPosition( i, _vector$b );
4799
4800 } else {
4801
4802 _vector$b.fromBufferAttribute( positionAttribute, i );
4803
4804 }
4805
4806 _vector$b.applyMatrix4( object.matrixWorld );
4807 this.expandByPoint( _vector$b );
4808
4809 }
4810
4811 } else {
4812
4813 if ( object.boundingBox !== undefined ) {
4814
4815 // object-level bounding box
4816
4817 if ( object.boundingBox === null ) {
4818
4819 object.computeBoundingBox();
4820
4821 }
4822
4823 _box$4.copy( object.boundingBox );
4824
4825
4826 } else {
4827
4828 // geometry-level bounding box
4829
4830 if ( geometry.boundingBox === null ) {
4831
4832 geometry.computeBoundingBox();
4833
4834 }
4835
4836 _box$4.copy( geometry.boundingBox );
4837
4838 }
4839
4840 _box$4.applyMatrix4( object.matrixWorld );
4841
4842 this.union( _box$4 );
4843
4844 }
4845
4846 }
4847
4848 const children = object.children;
4849
4850 for ( let i = 0, l = children.length; i < l; i ++ ) {
4851
4852 this.expandByObject( children[ i ], precise );
4853
4854 }
4855
4856 return this;
4857
4858 }
4859
4860 containsPoint( point ) {
4861
4862 return point.x < this.min.x || point.x > this.max.x ||
4863 point.y < this.min.y || point.y > this.max.y ||
4864 point.z < this.min.z || point.z > this.max.z ? false : true;
4865
4866 }
4867
4868 containsBox( box ) {
4869
4870 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
4871 this.min.y <= box.min.y && box.max.y <= this.max.y &&
4872 this.min.z <= box.min.z && box.max.z <= this.max.z;
4873
4874 }
4875
4877
4878 // This can potentially have a divide by zero if the box
4879 // has a size dimension of 0.
4880
4881 return target.set(
4882 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
4883 ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
4884 ( point.z - this.min.z ) / ( this.max.z - this.min.z )
4885 );
4886
4887 }
4888
4889 intersectsBox( box ) {
4890
4891 // using 6 splitting planes to rule out intersections.
4892 return box.max.x < this.min.x || box.min.x > this.max.x ||
4893 box.max.y < this.min.y || box.min.y > this.max.y ||
4894 box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
4895
4896 }
4897
4899
4900 // Find the point on the AABB closest to the sphere center.
4901 this.clampPoint( sphere.center, _vector$b );
4902
4903 // If that point is inside the sphere, the AABB and sphere intersect.
4904 return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
4905
4906 }
4907
4909
4910 // We compute the minimum and maximum dot product values. If those values
4911 // are on the same side (back or front) of the plane, then there is no intersection.
4912
4913 let min, max;
4914
4915 if ( plane.normal.x > 0 ) {
4916
4917 min = plane.normal.x * this.min.x;
4918 max = plane.normal.x * this.max.x;
4919
4920 } else {
4921
4922 min = plane.normal.x * this.max.x;
4923 max = plane.normal.x * this.min.x;
4924
4925 }
4926
4927 if ( plane.normal.y > 0 ) {
4928
4929 min += plane.normal.y * this.min.y;
4930 max += plane.normal.y * this.max.y;
4931
4932 } else {
4933
4934 min += plane.normal.y * this.max.y;
4935 max += plane.normal.y * this.min.y;
4936
4937 }
4938
4939 if ( plane.normal.z > 0 ) {
4940
4941 min += plane.normal.z * this.min.z;
4942 max += plane.normal.z * this.max.z;
4943
4944 } else {
4945
4946 min += plane.normal.z * this.max.z;
4947 max += plane.normal.z * this.min.z;
4948
4949 }
4950
4951 return ( min <= - plane.constant && max >= - plane.constant );
4952
4953 }
4954
4956
4957 if ( this.isEmpty() ) {
4958
4959 return false;
4960
4961 }
4962
4963 // compute box center and extents
4964 this.getCenter( _center );
4965 _extents.subVectors( this.max, _center );
4966
4967 // translate triangle to aabb origin
4968 _v0$2.subVectors( triangle.a, _center );
4969 _v1$7.subVectors( triangle.b, _center );
4970 _v2$4.subVectors( triangle.c, _center );
4971
4972 // compute edge vectors for triangle
4973 _f0.subVectors( _v1$7, _v0$2 );
4974 _f1.subVectors( _v2$4, _v1$7 );
4975 _f2.subVectors( _v0$2, _v2$4 );
4976
4977 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
4978 // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
4979 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
4980 let axes = [
4981 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
4982 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
4983 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
4984 ];
4985 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
4986
4987 return false;
4988
4989 }
4990
4991 // test 3 face normals from the aabb
4992 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
4993 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {
4994
4995 return false;
4996
4997 }
4998
4999 // finally testing the face normal of the triangle
5000 // use already existing triangle edge vectors here
5001 _triangleNormal.crossVectors( _f0, _f1 );
5003
5004 return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents );
5005
5006 }
5007
5008 clampPoint( point, target ) {
5009
5010 return target.copy( point ).clamp( this.min, this.max );
5011
5012 }
5013
5015
5016 return this.clampPoint( point, _vector$b ).distanceTo( point );
5017
5018 }
5019
5021
5022 if ( this.isEmpty() ) {
5023
5024 target.makeEmpty();
5025
5026 } else {
5027
5028 this.getCenter( target.center );
5029
5030 target.radius = this.getSize( _vector$b ).length() * 0.5;
5031
5032 }
5033
5034 return target;
5035
5036 }
5037
5038 intersect( box ) {
5039
5040 this.min.max( box.min );
5041 this.max.min( box.max );
5042
5043 // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
5044 if ( this.isEmpty() ) this.makeEmpty();
5045
5046 return this;
5047
5048 }
5049
5050 union( box ) {
5051
5052 this.min.min( box.min );
5053 this.max.max( box.max );
5054
5055 return this;
5056
5057 }
5058
5059 applyMatrix4( matrix ) {
5060
5061 // transform of empty box is an empty box.
5062 if ( this.isEmpty() ) return this;
5063
5064 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
5065 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
5066 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
5067 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
5068 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
5069 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
5070 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
5071 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
5072 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
5073
5074 this.setFromPoints( _points );
5075
5076 return this;
5077
5078 }
5079
5080 translate( offset ) {
5081
5082 this.min.add( offset );
5083 this.max.add( offset );
5084
5085 return this;
5086
5087 }
5088
5089 equals( box ) {
5090
5091 return box.min.equals( this.min ) && box.max.equals( this.max );
5092
5093 }
5094
5095 }
5096
5097 const _points = [
5098 /*@__PURE__*/ new Vector3(),
5099 /*@__PURE__*/ new Vector3(),
5100 /*@__PURE__*/ new Vector3(),
5101 /*@__PURE__*/ new Vector3(),
5102 /*@__PURE__*/ new Vector3(),
5103 /*@__PURE__*/ new Vector3(),
5104 /*@__PURE__*/ new Vector3(),
5105 /*@__PURE__*/ new Vector3()
5106 ];
5107
5108 const _vector$b = /*@__PURE__*/ new Vector3();
5109
5110 const _box$4 = /*@__PURE__*/ new Box3();
5111
5112 // triangle centered vertices
5113
5114 const _v0$2 = /*@__PURE__*/ new Vector3();
5115 const _v1$7 = /*@__PURE__*/ new Vector3();
5116 const _v2$4 = /*@__PURE__*/ new Vector3();
5117
5118 // triangle edge vectors
5119
5120 const _f0 = /*@__PURE__*/ new Vector3();
5121 const _f1 = /*@__PURE__*/ new Vector3();
5122 const _f2 = /*@__PURE__*/ new Vector3();
5123
5124 const _center = /*@__PURE__*/ new Vector3();
5125 const _extents = /*@__PURE__*/ new Vector3();
5126 const _triangleNormal = /*@__PURE__*/ new Vector3();
5127 const _testAxis = /*@__PURE__*/ new Vector3();
5128
5129 function satForAxes( axes, v0, v1, v2, extents ) {
5130
5131 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {
5132
5133 _testAxis.fromArray( axes, i );
5134 // project the aabb onto the separating axis
5135 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
5136 // project all 3 vertices of the triangle onto the separating axis
5137 const p0 = v0.dot( _testAxis );
5138 const p1 = v1.dot( _testAxis );
5139 const p2 = v2.dot( _testAxis );
5140 // actual test, basically see if either of the most extreme of the triangle points intersects r
5141 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
5142
5143 // points of the projected triangle are outside the projected half-length of the aabb
5144 // the axis is separating and we can exit
5145 return false;
5146
5147 }
5148
5149 }
5150
5151 return true;
5152
5153 }
5154
5155 const _box$3 = /*@__PURE__*/ new Box3();
5156 const _v1$6 = /*@__PURE__*/ new Vector3();
5157 const _v2$3 = /*@__PURE__*/ new Vector3();
5158
5159 class Sphere {
5160
5161 constructor( center = new Vector3(), radius = - 1 ) {
5162
5163 this.isSphere = true;
5164
5165 this.center = center;
5166 this.radius = radius;
5167
5168 }
5169
5170 set( center, radius ) {
5171
5172 this.center.copy( center );
5173 this.radius = radius;
5174
5175 return this;
5176
5177 }
5178
5180
5181 const center = this.center;
5182
5183 if ( optionalCenter !== undefined ) {
5184
5185 center.copy( optionalCenter );
5186
5187 } else {
5188
5189 _box$3.setFromPoints( points ).getCenter( center );
5190
5191 }
5192
5193 let maxRadiusSq = 0;
5194
5195 for ( let i = 0, il = points.length; i < il; i ++ ) {
5196
5197 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
5198
5199 }
5200
5201 this.radius = Math.sqrt( maxRadiusSq );
5202
5203 return this;
5204
5205 }
5206
5207 copy( sphere ) {
5208
5209 this.center.copy( sphere.center );
5210 this.radius = sphere.radius;
5211
5212 return this;
5213
5214 }
5215
5216 isEmpty() {
5217
5218 return ( this.radius < 0 );
5219
5220 }
5221
5222 makeEmpty() {
5223
5224 this.center.set( 0, 0, 0 );
5225 this.radius = - 1;
5226
5227 return this;
5228
5229 }
5230
5231 containsPoint( point ) {
5232
5233 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
5234
5235 }
5236
5238
5239 return ( point.distanceTo( this.center ) - this.radius );
5240
5241 }
5242
5244
5245 const radiusSum = this.radius + sphere.radius;
5246
5247 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
5248
5249 }
5250
5251 intersectsBox( box ) {
5252
5253 return box.intersectsSphere( this );
5254
5255 }
5256
5258
5259 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
5260
5261 }
5262
5263 clampPoint( point, target ) {
5264
5265 const deltaLengthSq = this.center.distanceToSquared( point );
5266
5267 target.copy( point );
5268
5269 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
5270
5271 target.sub( this.center ).normalize();
5272 target.multiplyScalar( this.radius ).add( this.center );
5273
5274 }
5275
5276 return target;
5277
5278 }
5279
5281
5282 if ( this.isEmpty() ) {
5283
5284 // Empty sphere produces empty bounding box
5285 target.makeEmpty();
5286 return target;
5287
5288 }
5289
5290 target.set( this.center, this.center );
5291 target.expandByScalar( this.radius );
5292
5293 return target;
5294
5295 }
5296
5297 applyMatrix4( matrix ) {
5298
5299 this.center.applyMatrix4( matrix );
5300 this.radius = this.radius * matrix.getMaxScaleOnAxis();
5301
5302 return this;
5303
5304 }
5305
5306 translate( offset ) {
5307
5308 this.center.add( offset );
5309
5310 return this;
5311
5312 }
5313
5314 expandByPoint( point ) {
5315
5316 if ( this.isEmpty() ) {
5317
5318 this.center.copy( point );
5319
5320 this.radius = 0;
5321
5322 return this;
5323
5324 }
5325
5326 _v1$6.subVectors( point, this.center );
5327
5328 const lengthSq = _v1$6.lengthSq();
5329
5330 if ( lengthSq > ( this.radius * this.radius ) ) {
5331
5332 // calculate the minimal sphere
5333
5334 const length = Math.sqrt( lengthSq );
5335
5336 const delta = ( length - this.radius ) * 0.5;
5337
5338 this.center.addScaledVector( _v1$6, delta / length );
5339
5340 this.radius += delta;
5341
5342 }
5343
5344 return this;
5345
5346 }
5347
5348 union( sphere ) {
5349
5350 if ( sphere.isEmpty() ) {
5351
5352 return this;
5353
5354 }
5355
5356 if ( this.isEmpty() ) {
5357
5358 this.copy( sphere );
5359
5360 return this;
5361
5362 }
5363
5364 if ( this.center.equals( sphere.center ) === true ) {
5365
5366 this.radius = Math.max( this.radius, sphere.radius );
5367
5368 } else {
5369
5370 _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius );
5371
5372 this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) );
5373
5374 this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) );
5375
5376 }
5377
5378 return this;
5379
5380 }
5381
5382 equals( sphere ) {
5383
5384 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
5385
5386 }
5387
5388 clone() {
5389
5390 return new this.constructor().copy( this );
5391
5392 }
5393
5394 }
5395
5396 const _vector$a = /*@__PURE__*/ new Vector3();
5397 const _segCenter = /*@__PURE__*/ new Vector3();
5398 const _segDir = /*@__PURE__*/ new Vector3();
5399 const _diff = /*@__PURE__*/ new Vector3();
5400
5401 const _edge1 = /*@__PURE__*/ new Vector3();
5402 const _edge2 = /*@__PURE__*/ new Vector3();
5403 const _normal$1 = /*@__PURE__*/ new Vector3();
5404
5405 class Ray {
5406
5407 constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {
5408
5409 this.origin = origin;
5410 this.direction = direction;
5411
5412 }
5413
5414 set( origin, direction ) {
5415
5416 this.origin.copy( origin );
5417 this.direction.copy( direction );
5418
5419 return this;
5420
5421 }
5422
5423 copy( ray ) {
5424
5425 this.origin.copy( ray.origin );
5426 this.direction.copy( ray.direction );
5427
5428 return this;
5429
5430 }
5431
5432 at( t, target ) {
5433
5434 return target.copy( this.origin ).addScaledVector( this.direction, t );
5435
5436 }
5437
5438 lookAt( v ) {
5439
5440 this.direction.copy( v ).sub( this.origin ).normalize();
5441
5442 return this;
5443
5444 }
5445
5446 recast( t ) {
5447
5448 this.origin.copy( this.at( t, _vector$a ) );
5449
5450 return this;
5451
5452 }
5453
5455
5456 target.subVectors( point, this.origin );
5457
5458 const directionDistance = target.dot( this.direction );
5459
5460 if ( directionDistance < 0 ) {
5461
5462 return target.copy( this.origin );
5463
5464 }
5465
5466 return target.copy( this.origin ).addScaledVector( this.direction, directionDistance );
5467
5468 }
5469
5471
5472 return Math.sqrt( this.distanceSqToPoint( point ) );
5473
5474 }
5475
5477
5478 const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );
5479
5480 // point behind the ray
5481
5482 if ( directionDistance < 0 ) {
5483
5484 return this.origin.distanceToSquared( point );
5485
5486 }
5487
5488 _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance );
5489
5490 return _vector$a.distanceToSquared( point );
5491
5492 }
5493
5495
5496 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h
5497 // It returns the min distance between the ray and the segment
5498 // defined by v0 and v1
5499 // It can also set two optional targets :
5500 // - The closest point on the ray
5501 // - The closest point on the segment
5502
5503 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
5504 _segDir.copy( v1 ).sub( v0 ).normalize();
5505 _diff.copy( this.origin ).sub( _segCenter );
5506
5507 const segExtent = v0.distanceTo( v1 ) * 0.5;
5508 const a01 = - this.direction.dot( _segDir );
5509 const b0 = _diff.dot( this.direction );
5510 const b1 = - _diff.dot( _segDir );
5511 const c = _diff.lengthSq();
5512 const det = Math.abs( 1 - a01 * a01 );
5513 let s0, s1, sqrDist, extDet;
5514
5515 if ( det > 0 ) {
5516
5517 // The ray and segment are not parallel.
5518
5519 s0 = a01 * b1 - b0;
5520 s1 = a01 * b0 - b1;
5521 extDet = segExtent * det;
5522
5523 if ( s0 >= 0 ) {
5524
5525 if ( s1 >= - extDet ) {
5526
5527 if ( s1 <= extDet ) {
5528
5529 // region 0
5530 // Minimum at interior points of ray and segment.
5531
5532 const invDet = 1 / det;
5533 s0 *= invDet;
5534 s1 *= invDet;
5535 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
5536
5537 } else {
5538
5539 // region 1
5540
5541 s1 = segExtent;
5542 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5543 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5544
5545 }
5546
5547 } else {
5548
5549 // region 5
5550
5551 s1 = - segExtent;
5552 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5553 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5554
5555 }
5556
5557 } else {
5558
5559 if ( s1 <= - extDet ) {
5560
5561 // region 4
5562
5563 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
5564 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
5565 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5566
5567 } else if ( s1 <= extDet ) {
5568
5569 // region 3
5570
5571 s0 = 0;
5572 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
5573 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
5574
5575 } else {
5576
5577 // region 2
5578
5579 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
5580 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
5581 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5582
5583 }
5584
5585 }
5586
5587 } else {
5588
5589 // Ray and segment are parallel.
5590
5591 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
5592 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
5593 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
5594
5595 }
5596
5597 if ( optionalPointOnRay ) {
5598
5599 optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );
5600
5601 }
5602
5603 if ( optionalPointOnSegment ) {
5604
5605 optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );
5606
5607 }
5608
5609 return sqrDist;
5610
5611 }
5612
5614
5615 _vector$a.subVectors( sphere.center, this.origin );
5616 const tca = _vector$a.dot( this.direction );
5617 const d2 = _vector$a.dot( _vector$a ) - tca * tca;
5618 const radius2 = sphere.radius * sphere.radius;
5619
5620 if ( d2 > radius2 ) return null;
5621
5622 const thc = Math.sqrt( radius2 - d2 );
5623
5624 // t0 = first intersect point - entrance on front of sphere
5625 const t0 = tca - thc;
5626
5627 // t1 = second intersect point - exit point on back of sphere
5628 const t1 = tca + thc;
5629
5630 // test to see if t1 is behind the ray - if so, return null
5631 if ( t1 < 0 ) return null;
5632
5633 // test to see if t0 is behind the ray:
5634 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
5635 // in order to always return an intersect point that is in front of the ray.
5636 if ( t0 < 0 ) return this.at( t1, target );
5637
5638 // else t0 is in front of the ray, so return the first collision point scaled by t0
5639 return this.at( t0, target );
5640
5641 }
5642
5644
5645 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
5646
5647 }
5648
5650
5651 const denominator = plane.normal.dot( this.direction );
5652
5653 if ( denominator === 0 ) {
5654
5655 // line is coplanar, return origin
5656 if ( plane.distanceToPoint( this.origin ) === 0 ) {
5657
5658 return 0;
5659
5660 }
5661
5662 // Null is preferable to undefined since undefined means.... it is undefined
5663
5664 return null;
5665
5666 }
5667
5668 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
5669
5670 // Return if the ray never intersects the plane
5671
5672 return t >= 0 ? t : null;
5673
5674 }
5675
5677
5678 const t = this.distanceToPlane( plane );
5679
5680 if ( t === null ) {
5681
5682 return null;
5683
5684 }
5685
5686 return this.at( t, target );
5687
5688 }
5689
5691
5692 // check if the ray lies on the plane first
5693
5694 const distToPoint = plane.distanceToPoint( this.origin );
5695
5696 if ( distToPoint === 0 ) {
5697
5698 return true;
5699
5700 }
5701
5702 const denominator = plane.normal.dot( this.direction );
5703
5704 if ( denominator * distToPoint < 0 ) {
5705
5706 return true;
5707
5708 }
5709
5710 // ray origin is behind the plane (and is pointing behind it)
5711
5712 return false;
5713
5714 }
5715
5716 intersectBox( box, target ) {
5717
5719
5720 const invdirx = 1 / this.direction.x,
5721 invdiry = 1 / this.direction.y,
5722 invdirz = 1 / this.direction.z;
5723
5724 const origin = this.origin;
5725
5726 if ( invdirx >= 0 ) {
5727
5728 tmin = ( box.min.x - origin.x ) * invdirx;
5729 tmax = ( box.max.x - origin.x ) * invdirx;
5730
5731 } else {
5732
5733 tmin = ( box.max.x - origin.x ) * invdirx;
5734 tmax = ( box.min.x - origin.x ) * invdirx;
5735
5736 }
5737
5738 if ( invdiry >= 0 ) {
5739
5740 tymin = ( box.min.y - origin.y ) * invdiry;
5741 tymax = ( box.max.y - origin.y ) * invdiry;
5742
5743 } else {
5744
5745 tymin = ( box.max.y - origin.y ) * invdiry;
5746 tymax = ( box.min.y - origin.y ) * invdiry;
5747
5748 }
5749
5750 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
5751
5752 if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;
5753
5754 if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;
5755
5756 if ( invdirz >= 0 ) {
5757
5758 tzmin = ( box.min.z - origin.z ) * invdirz;
5759 tzmax = ( box.max.z - origin.z ) * invdirz;
5760
5761 } else {
5762
5763 tzmin = ( box.max.z - origin.z ) * invdirz;
5764 tzmax = ( box.min.z - origin.z ) * invdirz;
5765
5766 }
5767
5768 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
5769
5770 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
5771
5772 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
5773
5774 //return point closest to the ray (positive side)
5775
5776 if ( tmax < 0 ) return null;
5777
5778 return this.at( tmin >= 0 ? tmin : tmax, target );
5779
5780 }
5781
5782 intersectsBox( box ) {
5783
5784 return this.intersectBox( box, _vector$a ) !== null;
5785
5786 }
5787
5789
5790 // Compute the offset origin, edges, and normal.
5791
5792 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
5793
5794 _edge1.subVectors( b, a );
5795 _edge2.subVectors( c, a );
5796 _normal$1.crossVectors( _edge1, _edge2 );
5797
5798 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
5799 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
5800 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
5801 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
5802 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
5803 let DdN = this.direction.dot( _normal$1 );
5804 let sign;
5805
5806 if ( DdN > 0 ) {
5807
5808 if ( backfaceCulling ) return null;
5809 sign = 1;
5810
5811 } else if ( DdN < 0 ) {
5812
5813 sign = - 1;
5814 DdN = - DdN;
5815
5816 } else {
5817
5818 return null;
5819
5820 }
5821
5822 _diff.subVectors( this.origin, a );
5823 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
5824
5825 // b1 < 0, no intersection
5826 if ( DdQxE2 < 0 ) {
5827
5828 return null;
5829
5830 }
5831
5832 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
5833
5834 // b2 < 0, no intersection
5835 if ( DdE1xQ < 0 ) {
5836
5837 return null;
5838
5839 }
5840
5841 // b1+b2 > 1, no intersection
5842 if ( DdQxE2 + DdE1xQ > DdN ) {
5843
5844 return null;
5845
5846 }
5847
5848 // Line intersects triangle, check if ray does.
5849 const QdN = - sign * _diff.dot( _normal$1 );
5850
5851 // t < 0, no intersection
5852 if ( QdN < 0 ) {
5853
5854 return null;
5855
5856 }
5857
5858 // Ray intersects triangle.
5859 return this.at( QdN / DdN, target );
5860
5861 }
5862
5864
5865 this.origin.applyMatrix4( matrix4 );
5866 this.direction.transformDirection( matrix4 );
5867
5868 return this;
5869
5870 }
5871
5872 equals( ray ) {
5873
5874 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
5875
5876 }
5877
5878 clone() {
5879
5880 return new this.constructor().copy( this );
5881
5882 }
5883
5884 }
5885
5886 class Matrix4 {
5887
5888 constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5889
5890 Matrix4.prototype.isMatrix4 = true;
5891
5892 this.elements = [
5893
5894 1, 0, 0, 0,
5895 0, 1, 0, 0,
5896 0, 0, 1, 0,
5897 0, 0, 0, 1
5898
5899 ];
5900
5901 if ( n11 !== undefined ) {
5902
5903 this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );
5904
5905 }
5906
5907 }
5908
5909 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
5910
5911 const te = this.elements;
5912
5913 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
5914 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
5915 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
5916 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
5917
5918 return this;
5919
5920 }
5921
5922 identity() {
5923
5924 this.set(
5925
5926 1, 0, 0, 0,
5927 0, 1, 0, 0,
5928 0, 0, 1, 0,
5929 0, 0, 0, 1
5930
5931 );
5932
5933 return this;
5934
5935 }
5936
5937 clone() {
5938
5939 return new Matrix4().fromArray( this.elements );
5940
5941 }
5942
5943 copy( m ) {
5944
5945 const te = this.elements;
5946 const me = m.elements;
5947
5948 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
5949 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
5950 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
5951 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
5952
5953 return this;
5954
5955 }
5956
5957 copyPosition( m ) {
5958
5959 const te = this.elements, me = m.elements;
5960
5961 te[ 12 ] = me[ 12 ];
5962 te[ 13 ] = me[ 13 ];
5963 te[ 14 ] = me[ 14 ];
5964
5965 return this;
5966
5967 }
5968
5969 setFromMatrix3( m ) {
5970
5971 const me = m.elements;
5972
5973 this.set(
5974
5975 me[ 0 ], me[ 3 ], me[ 6 ], 0,
5976 me[ 1 ], me[ 4 ], me[ 7 ], 0,
5977 me[ 2 ], me[ 5 ], me[ 8 ], 0,
5978 0, 0, 0, 1
5979
5980 );
5981
5982 return this;
5983
5984 }
5985
5987
5988 xAxis.setFromMatrixColumn( this, 0 );
5989 yAxis.setFromMatrixColumn( this, 1 );
5990 zAxis.setFromMatrixColumn( this, 2 );
5991
5992 return this;
5993
5994 }
5995
5996 makeBasis( xAxis, yAxis, zAxis ) {
5997
5998 this.set(
5999 xAxis.x, yAxis.x, zAxis.x, 0,
6000 xAxis.y, yAxis.y, zAxis.y, 0,
6001 xAxis.z, yAxis.z, zAxis.z, 0,
6002 0, 0, 0, 1
6003 );
6004
6005 return this;
6006
6007 }
6008
6009 extractRotation( m ) {
6010
6011 // this method does not support reflection matrices
6012
6013 const te = this.elements;
6014 const me = m.elements;
6015
6016 const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();
6017 const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();
6018 const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();
6019
6020 te[ 0 ] = me[ 0 ] * scaleX;
6021 te[ 1 ] = me[ 1 ] * scaleX;
6022 te[ 2 ] = me[ 2 ] * scaleX;
6023 te[ 3 ] = 0;
6024
6025 te[ 4 ] = me[ 4 ] * scaleY;
6026 te[ 5 ] = me[ 5 ] * scaleY;
6027 te[ 6 ] = me[ 6 ] * scaleY;
6028 te[ 7 ] = 0;
6029
6030 te[ 8 ] = me[ 8 ] * scaleZ;
6031 te[ 9 ] = me[ 9 ] * scaleZ;
6032 te[ 10 ] = me[ 10 ] * scaleZ;
6033 te[ 11 ] = 0;
6034
6035 te[ 12 ] = 0;
6036 te[ 13 ] = 0;
6037 te[ 14 ] = 0;
6038 te[ 15 ] = 1;
6039
6040 return this;
6041
6042 }
6043
6045
6046 const te = this.elements;
6047
6048 const x = euler.x, y = euler.y, z = euler.z;
6049 const a = Math.cos( x ), b = Math.sin( x );
6050 const c = Math.cos( y ), d = Math.sin( y );
6051 const e = Math.cos( z ), f = Math.sin( z );
6052
6053 if ( euler.order === 'XYZ' ) {
6054
6055 const ae = a * e, af = a * f, be = b * e, bf = b * f;
6056
6057 te[ 0 ] = c * e;
6058 te[ 4 ] = - c * f;
6059 te[ 8 ] = d;
6060
6061 te[ 1 ] = af + be * d;
6062 te[ 5 ] = ae - bf * d;
6063 te[ 9 ] = - b * c;
6064
6065 te[ 2 ] = bf - ae * d;
6066 te[ 6 ] = be + af * d;
6067 te[ 10 ] = a * c;
6068
6069 } else if ( euler.order === 'YXZ' ) {
6070
6071 const ce = c * e, cf = c * f, de = d * e, df = d * f;
6072
6073 te[ 0 ] = ce + df * b;
6074 te[ 4 ] = de * b - cf;
6075 te[ 8 ] = a * d;
6076
6077 te[ 1 ] = a * f;
6078 te[ 5 ] = a * e;
6079 te[ 9 ] = - b;
6080
6081 te[ 2 ] = cf * b - de;
6082 te[ 6 ] = df + ce * b;
6083 te[ 10 ] = a * c;
6084
6085 } else if ( euler.order === 'ZXY' ) {
6086
6087 const ce = c * e, cf = c * f, de = d * e, df = d * f;
6088
6089 te[ 0 ] = ce - df * b;
6090 te[ 4 ] = - a * f;
6091 te[ 8 ] = de + cf * b;
6092
6093 te[ 1 ] = cf + de * b;
6094 te[ 5 ] = a * e;
6095 te[ 9 ] = df - ce * b;
6096
6097 te[ 2 ] = - a * d;
6098 te[ 6 ] = b;
6099 te[ 10 ] = a * c;
6100
6101 } else if ( euler.order === 'ZYX' ) {
6102
6103 const ae = a * e, af = a * f, be = b * e, bf = b * f;
6104
6105 te[ 0 ] = c * e;
6106 te[ 4 ] = be * d - af;
6107 te[ 8 ] = ae * d + bf;
6108
6109 te[ 1 ] = c * f;
6110 te[ 5 ] = bf * d + ae;
6111 te[ 9 ] = af * d - be;
6112
6113 te[ 2 ] = - d;
6114 te[ 6 ] = b * c;
6115 te[ 10 ] = a * c;
6116
6117 } else if ( euler.order === 'YZX' ) {
6118
6119 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
6120
6121 te[ 0 ] = c * e;
6122 te[ 4 ] = bd - ac * f;
6123 te[ 8 ] = bc * f + ad;
6124
6125 te[ 1 ] = f;
6126 te[ 5 ] = a * e;
6127 te[ 9 ] = - b * e;
6128
6129 te[ 2 ] = - d * e;
6130 te[ 6 ] = ad * f + bc;
6131 te[ 10 ] = ac - bd * f;
6132
6133 } else if ( euler.order === 'XZY' ) {
6134
6135 const ac = a * c, ad = a * d, bc = b * c, bd = b * d;
6136
6137 te[ 0 ] = c * e;
6138 te[ 4 ] = - f;
6139 te[ 8 ] = d * e;
6140
6141 te[ 1 ] = ac * f + bd;
6142 te[ 5 ] = a * e;
6143 te[ 9 ] = ad * f - bc;
6144
6145 te[ 2 ] = bc * f - ad;
6146 te[ 6 ] = b * e;
6147 te[ 10 ] = bd * f + ac;
6148
6149 }
6150
6151 // bottom row
6152 te[ 3 ] = 0;
6153 te[ 7 ] = 0;
6154 te[ 11 ] = 0;
6155
6156 // last column
6157 te[ 12 ] = 0;
6158 te[ 13 ] = 0;
6159 te[ 14 ] = 0;
6160 te[ 15 ] = 1;
6161
6162 return this;
6163
6164 }
6165
6167
6168 return this.compose( _zero, q, _one );
6169
6170 }
6171
6172 lookAt( eye, target, up ) {
6173
6174 const te = this.elements;
6175
6176 _z.subVectors( eye, target );
6177
6178 if ( _z.lengthSq() === 0 ) {
6179
6180 // eye and target are in the same position
6181
6182 _z.z = 1;
6183
6184 }
6185
6186 _z.normalize();
6187 _x.crossVectors( up, _z );
6188
6189 if ( _x.lengthSq() === 0 ) {
6190
6191 // up and z are parallel
6192
6193 if ( Math.abs( up.z ) === 1 ) {
6194
6195 _z.x += 0.0001;
6196
6197 } else {
6198
6199 _z.z += 0.0001;
6200
6201 }
6202
6203 _z.normalize();
6204 _x.crossVectors( up, _z );
6205
6206 }
6207
6208 _x.normalize();
6209 _y.crossVectors( _z, _x );
6210
6211 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
6212 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
6213 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
6214
6215 return this;
6216
6217 }
6218
6219 multiply( m ) {
6220
6221 return this.multiplyMatrices( this, m );
6222
6223 }
6224
6225 premultiply( m ) {
6226
6227 return this.multiplyMatrices( m, this );
6228
6229 }
6230
6231 multiplyMatrices( a, b ) {
6232
6233 const ae = a.elements;
6234 const be = b.elements;
6235 const te = this.elements;
6236
6237 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
6238 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
6239 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
6240 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
6241
6242 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
6243 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
6244 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
6245 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
6246
6247 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
6248 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
6249 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
6250 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
6251
6252 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
6253 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
6254 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
6255 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
6256
6257 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
6258 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
6259 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
6260 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
6261
6262 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
6263 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
6264 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
6265 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
6266
6267 return this;
6268
6269 }
6270
6271 multiplyScalar( s ) {
6272
6273 const te = this.elements;
6274
6275 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
6276 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
6277 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
6278 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
6279
6280 return this;
6281
6282 }
6283
6284 determinant() {
6285
6286 const te = this.elements;
6287
6288 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
6289 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
6290 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
6291 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
6292
6293 //TODO: make this more efficient
6294 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
6295
6296 return (
6297 n41 * (
6298 + n14 * n23 * n32
6299 - n13 * n24 * n32
6300 - n14 * n22 * n33
6301 + n12 * n24 * n33
6302 + n13 * n22 * n34
6303 - n12 * n23 * n34
6304 ) +
6305 n42 * (
6306 + n11 * n23 * n34
6307 - n11 * n24 * n33
6308 + n14 * n21 * n33
6309 - n13 * n21 * n34
6310 + n13 * n24 * n31
6311 - n14 * n23 * n31
6312 ) +
6313 n43 * (
6314 + n11 * n24 * n32
6315 - n11 * n22 * n34
6316 - n14 * n21 * n32
6317 + n12 * n21 * n34
6318 + n14 * n22 * n31
6319 - n12 * n24 * n31
6320 ) +
6321 n44 * (
6322 - n13 * n22 * n31
6323 - n11 * n23 * n32
6324 + n11 * n22 * n33
6325 + n13 * n21 * n32
6326 - n12 * n21 * n33
6327 + n12 * n23 * n31
6328 )
6329
6330 );
6331
6332 }
6333
6334 transpose() {
6335
6336 const te = this.elements;
6337 let tmp;
6338
6339 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
6340 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
6341 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
6342
6343 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
6344 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
6345 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
6346
6347 return this;
6348
6349 }
6350
6351 setPosition( x, y, z ) {
6352
6353 const te = this.elements;
6354
6355 if ( x.isVector3 ) {
6356
6357 te[ 12 ] = x.x;
6358 te[ 13 ] = x.y;
6359 te[ 14 ] = x.z;
6360
6361 } else {
6362
6363 te[ 12 ] = x;
6364 te[ 13 ] = y;
6365 te[ 14 ] = z;
6366
6367 }
6368
6369 return this;
6370
6371 }
6372
6373 invert() {
6374
6375 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
6376 const te = this.elements,
6377
6378 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],
6379 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],
6380 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],
6381 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],
6382
6383 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
6384 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
6385 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
6386 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
6387
6388 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
6389
6390 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
6391
6392 const detInv = 1 / det;
6393
6394 te[ 0 ] = t11 * detInv;
6395 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
6396 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
6397 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
6398
6399 te[ 4 ] = t12 * detInv;
6400 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
6401 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
6402 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
6403
6404 te[ 8 ] = t13 * detInv;
6405 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
6406 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
6407 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
6408
6409 te[ 12 ] = t14 * detInv;
6410 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
6411 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
6412 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
6413
6414 return this;
6415
6416 }
6417
6418 scale( v ) {
6419
6420 const te = this.elements;
6421 const x = v.x, y = v.y, z = v.z;
6422
6423 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
6424 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
6425 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
6426 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
6427
6428 return this;
6429
6430 }
6431
6433
6434 const te = this.elements;
6435
6436 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
6437 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
6438 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
6439
6440 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
6441
6442 }
6443
6444 makeTranslation( x, y, z ) {
6445
6446 if ( x.isVector3 ) {
6447
6448 this.set(
6449
6450 1, 0, 0, x.x,
6451 0, 1, 0, x.y,
6452 0, 0, 1, x.z,
6453 0, 0, 0, 1
6454
6455 );
6456
6457 } else {
6458
6459 this.set(
6460
6461 1, 0, 0, x,
6462 0, 1, 0, y,
6463 0, 0, 1, z,
6464 0, 0, 0, 1
6465
6466 );
6467
6468 }
6469
6470 return this;
6471
6472 }
6473
6474 makeRotationX( theta ) {
6475
6476 const c = Math.cos( theta ), s = Math.sin( theta );
6477
6478 this.set(
6479
6480 1, 0, 0, 0,
6481 0, c, - s, 0,
6482 0, s, c, 0,
6483 0, 0, 0, 1
6484
6485 );
6486
6487 return this;
6488
6489 }
6490
6491 makeRotationY( theta ) {
6492
6493 const c = Math.cos( theta ), s = Math.sin( theta );
6494
6495 this.set(
6496
6497 c, 0, s, 0,
6498 0, 1, 0, 0,
6499 - s, 0, c, 0,
6500 0, 0, 0, 1
6501
6502 );
6503
6504 return this;
6505
6506 }
6507
6508 makeRotationZ( theta ) {
6509
6510 const c = Math.cos( theta ), s = Math.sin( theta );
6511
6512 this.set(
6513
6514 c, - s, 0, 0,
6515 s, c, 0, 0,
6516 0, 0, 1, 0,
6517 0, 0, 0, 1
6518
6519 );
6520
6521 return this;
6522
6523 }
6524
6525 makeRotationAxis( axis, angle ) {
6526
6527 // Based on http://www.gamedev.net/reference/articles/article1199.asp
6528
6529 const c = Math.cos( angle );
6530 const s = Math.sin( angle );
6531 const t = 1 - c;
6532 const x = axis.x, y = axis.y, z = axis.z;
6533 const tx = t * x, ty = t * y;
6534
6535 this.set(
6536
6537 tx * x + c, tx * y - s * z, tx * z + s * y, 0,
6538 tx * y + s * z, ty * y + c, ty * z - s * x, 0,
6539 tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
6540 0, 0, 0, 1
6541
6542 );
6543
6544 return this;
6545
6546 }
6547
6548 makeScale( x, y, z ) {
6549
6550 this.set(
6551
6552 x, 0, 0, 0,
6553 0, y, 0, 0,
6554 0, 0, z, 0,
6555 0, 0, 0, 1
6556
6557 );
6558
6559 return this;
6560
6561 }
6562
6563 makeShear( xy, xz, yx, yz, zx, zy ) {
6564
6565 this.set(
6566
6567 1, yx, zx, 0,
6568 xy, 1, zy, 0,
6569 xz, yz, 1, 0,
6570 0, 0, 0, 1
6571
6572 );
6573
6574 return this;
6575
6576 }
6577
6579
6580 const te = this.elements;
6581
6582 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
6583 const x2 = x + x, y2 = y + y, z2 = z + z;
6584 const xx = x * x2, xy = x * y2, xz = x * z2;
6585 const yy = y * y2, yz = y * z2, zz = z * z2;
6586 const wx = w * x2, wy = w * y2, wz = w * z2;
6587
6588 const sx = scale.x, sy = scale.y, sz = scale.z;
6589
6590 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx;
6591 te[ 1 ] = ( xy + wz ) * sx;
6592 te[ 2 ] = ( xz - wy ) * sx;
6593 te[ 3 ] = 0;
6594
6595 te[ 4 ] = ( xy - wz ) * sy;
6596 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy;
6597 te[ 6 ] = ( yz + wx ) * sy;
6598 te[ 7 ] = 0;
6599
6600 te[ 8 ] = ( xz + wy ) * sz;
6601 te[ 9 ] = ( yz - wx ) * sz;
6602 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz;
6603 te[ 11 ] = 0;
6604
6605 te[ 12 ] = position.x;
6606 te[ 13 ] = position.y;
6607 te[ 14 ] = position.z;
6608 te[ 15 ] = 1;
6609
6610 return this;
6611
6612 }
6613
6615
6616 const te = this.elements;
6617
6618 let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
6619 const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
6620 const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
6621
6622 // if determine is negative, we need to invert one scale
6623 const det = this.determinant();
6624 if ( det < 0 ) sx = - sx;
6625
6626 position.x = te[ 12 ];
6627 position.y = te[ 13 ];
6628 position.z = te[ 14 ];
6629
6630 // scale the rotation part
6631 _m1$2.copy( this );
6632
6633 const invSX = 1 / sx;
6634 const invSY = 1 / sy;
6635 const invSZ = 1 / sz;
6636
6637 _m1$2.elements[ 0 ] *= invSX;
6638 _m1$2.elements[ 1 ] *= invSX;
6639 _m1$2.elements[ 2 ] *= invSX;
6640
6641 _m1$2.elements[ 4 ] *= invSY;
6642 _m1$2.elements[ 5 ] *= invSY;
6643 _m1$2.elements[ 6 ] *= invSY;
6644
6645 _m1$2.elements[ 8 ] *= invSZ;
6646 _m1$2.elements[ 9 ] *= invSZ;
6647 _m1$2.elements[ 10 ] *= invSZ;
6648
6649 quaternion.setFromRotationMatrix( _m1$2 );
6650
6651 scale.x = sx;
6652 scale.y = sy;
6653 scale.z = sz;
6654
6655 return this;
6656
6657 }
6658
6660
6661 const te = this.elements;
6662 const x = 2 * near / ( right - left );
6663 const y = 2 * near / ( top - bottom );
6664
6665 const a = ( right + left ) / ( right - left );
6666 const b = ( top + bottom ) / ( top - bottom );
6667
6668 let c, d;
6669
6671
6672 c = - ( far + near ) / ( far - near );
6673 d = ( - 2 * far * near ) / ( far - near );
6674
6675 } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6676
6677 c = - far / ( far - near );
6678 d = ( - far * near ) / ( far - near );
6679
6680 } else {
6681
6682 throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );
6683
6684 }
6685
6686 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
6687 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
6688 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
6689 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
6690
6691 return this;
6692
6693 }
6694
6696
6697 const te = this.elements;
6698 const w = 1.0 / ( right - left );
6699 const h = 1.0 / ( top - bottom );
6700 const p = 1.0 / ( far - near );
6701
6702 const x = ( right + left ) * w;
6703 const y = ( top + bottom ) * h;
6704
6705 let z, zInv;
6706
6708
6709 z = ( far + near ) * p;
6710 zInv = - 2 * p;
6711
6712 } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
6713
6714 z = near * p;
6715 zInv = - 1 * p;
6716
6717 } else {
6718
6719 throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );
6720
6721 }
6722
6723 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
6724 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
6725 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z;
6726 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
6727
6728 return this;
6729
6730 }
6731
6732 equals( matrix ) {
6733
6734 const te = this.elements;
6735 const me = matrix.elements;
6736
6737 for ( let i = 0; i < 16; i ++ ) {
6738
6739 if ( te[ i ] !== me[ i ] ) return false;
6740
6741 }
6742
6743 return true;
6744
6745 }
6746
6747 fromArray( array, offset = 0 ) {
6748
6749 for ( let i = 0; i < 16; i ++ ) {
6750
6751 this.elements[ i ] = array[ i + offset ];
6752
6753 }
6754
6755 return this;
6756
6757 }
6758
6759 toArray( array = [], offset = 0 ) {
6760
6761 const te = this.elements;
6762
6763 array[ offset ] = te[ 0 ];
6764 array[ offset + 1 ] = te[ 1 ];
6765 array[ offset + 2 ] = te[ 2 ];
6766 array[ offset + 3 ] = te[ 3 ];
6767
6768 array[ offset + 4 ] = te[ 4 ];
6769 array[ offset + 5 ] = te[ 5 ];
6770 array[ offset + 6 ] = te[ 6 ];
6771 array[ offset + 7 ] = te[ 7 ];
6772
6773 array[ offset + 8 ] = te[ 8 ];
6774 array[ offset + 9 ] = te[ 9 ];
6775 array[ offset + 10 ] = te[ 10 ];
6776 array[ offset + 11 ] = te[ 11 ];
6777
6778 array[ offset + 12 ] = te[ 12 ];
6779 array[ offset + 13 ] = te[ 13 ];
6780 array[ offset + 14 ] = te[ 14 ];
6781 array[ offset + 15 ] = te[ 15 ];
6782
6783 return array;
6784
6785 }
6786
6787 }
6788
6789 const _v1$5 = /*@__PURE__*/ new Vector3();
6790 const _m1$2 = /*@__PURE__*/ new Matrix4();
6791 const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );
6792 const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );
6793 const _x = /*@__PURE__*/ new Vector3();
6794 const _y = /*@__PURE__*/ new Vector3();
6795 const _z = /*@__PURE__*/ new Vector3();
6796
6797 const _matrix$1 = /*@__PURE__*/ new Matrix4();
6798 const _quaternion$3 = /*@__PURE__*/ new Quaternion();
6799
6800 class Euler {
6801
6802 constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {
6803
6804 this.isEuler = true;
6805
6806 this._x = x;
6807 this._y = y;
6808 this._z = z;
6809 this._order = order;
6810
6811 }
6812
6813 get x() {
6814
6815 return this._x;
6816
6817 }
6818
6819 set x( value ) {
6820
6821 this._x = value;
6822 this._onChangeCallback();
6823
6824 }
6825
6826 get y() {
6827
6828 return this._y;
6829
6830 }
6831
6832 set y( value ) {
6833
6834 this._y = value;
6835 this._onChangeCallback();
6836
6837 }
6838
6839 get z() {
6840
6841 return this._z;
6842
6843 }
6844
6845 set z( value ) {
6846
6847 this._z = value;
6848 this._onChangeCallback();
6849
6850 }
6851
6852 get order() {
6853
6854 return this._order;
6855
6856 }
6857
6858 set order( value ) {
6859
6860 this._order = value;
6861 this._onChangeCallback();
6862
6863 }
6864
6865 set( x, y, z, order = this._order ) {
6866
6867 this._x = x;
6868 this._y = y;
6869 this._z = z;
6870 this._order = order;
6871
6872 this._onChangeCallback();
6873
6874 return this;
6875
6876 }
6877
6878 clone() {
6879
6880 return new this.constructor( this._x, this._y, this._z, this._order );
6881
6882 }
6883
6884 copy( euler ) {
6885
6886 this._x = euler._x;
6887 this._y = euler._y;
6888 this._z = euler._z;
6889 this._order = euler._order;
6890
6891 this._onChangeCallback();
6892
6893 return this;
6894
6895 }
6896
6897 setFromRotationMatrix( m, order = this._order, update = true ) {
6898
6899 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
6900
6901 const te = m.elements;
6902 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
6903 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
6904 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
6905
6906 switch ( order ) {
6907
6908 case 'XYZ':
6909
6910 this._y = Math.asin( clamp( m13, - 1, 1 ) );
6911
6912 if ( Math.abs( m13 ) < 0.9999999 ) {
6913
6914 this._x = Math.atan2( - m23, m33 );
6915 this._z = Math.atan2( - m12, m11 );
6916
6917 } else {
6918
6919 this._x = Math.atan2( m32, m22 );
6920 this._z = 0;
6921
6922 }
6923
6924 break;
6925
6926 case 'YXZ':
6927
6928 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
6929
6930 if ( Math.abs( m23 ) < 0.9999999 ) {
6931
6932 this._y = Math.atan2( m13, m33 );
6933 this._z = Math.atan2( m21, m22 );
6934
6935 } else {
6936
6937 this._y = Math.atan2( - m31, m11 );
6938 this._z = 0;
6939
6940 }
6941
6942 break;
6943
6944 case 'ZXY':
6945
6946 this._x = Math.asin( clamp( m32, - 1, 1 ) );
6947
6948 if ( Math.abs( m32 ) < 0.9999999 ) {
6949
6950 this._y = Math.atan2( - m31, m33 );
6951 this._z = Math.atan2( - m12, m22 );
6952
6953 } else {
6954
6955 this._y = 0;
6956 this._z = Math.atan2( m21, m11 );
6957
6958 }
6959
6960 break;
6961
6962 case 'ZYX':
6963
6964 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
6965
6966 if ( Math.abs( m31 ) < 0.9999999 ) {
6967
6968 this._x = Math.atan2( m32, m33 );
6969 this._z = Math.atan2( m21, m11 );
6970
6971 } else {
6972
6973 this._x = 0;
6974 this._z = Math.atan2( - m12, m22 );
6975
6976 }
6977
6978 break;
6979
6980 case 'YZX':
6981
6982 this._z = Math.asin( clamp( m21, - 1, 1 ) );
6983
6984 if ( Math.abs( m21 ) < 0.9999999 ) {
6985
6986 this._x = Math.atan2( - m23, m22 );
6987 this._y = Math.atan2( - m31, m11 );
6988
6989 } else {
6990
6991 this._x = 0;
6992 this._y = Math.atan2( m13, m33 );
6993
6994 }
6995
6996 break;
6997
6998 case 'XZY':
6999
7000 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
7001
7002 if ( Math.abs( m12 ) < 0.9999999 ) {
7003
7004 this._x = Math.atan2( m32, m22 );
7005 this._y = Math.atan2( m13, m11 );
7006
7007 } else {
7008
7009 this._x = Math.atan2( - m23, m33 );
7010 this._y = 0;
7011
7012 }
7013
7014 break;
7015
7016 default:
7017
7018 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );
7019
7020 }
7021
7022 this._order = order;
7023
7024 if ( update === true ) this._onChangeCallback();
7025
7026 return this;
7027
7028 }
7029
7030 setFromQuaternion( q, order, update ) {
7031
7032 _matrix$1.makeRotationFromQuaternion( q );
7033
7034 return this.setFromRotationMatrix( _matrix$1, order, update );
7035
7036 }
7037
7038 setFromVector3( v, order = this._order ) {
7039
7040 return this.set( v.x, v.y, v.z, order );
7041
7042 }
7043
7044 reorder( newOrder ) {
7045
7046 // WARNING: this discards revolution information -bhouston
7047
7048 _quaternion$3.setFromEuler( this );
7049
7051
7052 }
7053
7054 equals( euler ) {
7055
7056 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
7057
7058 }
7059
7060 fromArray( array ) {
7061
7062 this._x = array[ 0 ];
7063 this._y = array[ 1 ];
7064 this._z = array[ 2 ];
7065 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
7066
7067 this._onChangeCallback();
7068
7069 return this;
7070
7071 }
7072
7073 toArray( array = [], offset = 0 ) {
7074
7075 array[ offset ] = this._x;
7076 array[ offset + 1 ] = this._y;
7077 array[ offset + 2 ] = this._z;
7078 array[ offset + 3 ] = this._order;
7079
7080 return array;
7081
7082 }
7083
7084 _onChange( callback ) {
7085
7087
7088 return this;
7089
7090 }
7091
7093
7094 *[ Symbol.iterator ]() {
7095
7096 yield this._x;
7097 yield this._y;
7098 yield this._z;
7099 yield this._order;
7100
7101 }
7102
7103 }
7104
7105 Euler.DEFAULT_ORDER = 'XYZ';
7106
7107 class Layers {
7108
7109 constructor() {
7110
7111 this.mask = 1 | 0;
7112
7113 }
7114
7115 set( channel ) {
7116
7117 this.mask = ( 1 << channel | 0 ) >>> 0;
7118
7119 }
7120
7121 enable( channel ) {
7122
7123 this.mask |= 1 << channel | 0;
7124
7125 }
7126
7127 enableAll() {
7128
7129 this.mask = 0xffffffff | 0;
7130
7131 }
7132
7133 toggle( channel ) {
7134
7135 this.mask ^= 1 << channel | 0;
7136
7137 }
7138
7139 disable( channel ) {
7140
7141 this.mask &= ~ ( 1 << channel | 0 );
7142
7143 }
7144
7145 disableAll() {
7146
7147 this.mask = 0;
7148
7149 }
7150
7151 test( layers ) {
7152
7153 return ( this.mask & layers.mask ) !== 0;
7154
7155 }
7156
7157 isEnabled( channel ) {
7158
7159 return ( this.mask & ( 1 << channel | 0 ) ) !== 0;
7160
7161 }
7162
7163 }
7164
7165 let _object3DId = 0;
7166
7167 const _v1$4 = /*@__PURE__*/ new Vector3();
7168 const _q1 = /*@__PURE__*/ new Quaternion();
7169 const _m1$1 = /*@__PURE__*/ new Matrix4();
7170 const _target = /*@__PURE__*/ new Vector3();
7171
7172 const _position$3 = /*@__PURE__*/ new Vector3();
7173 const _scale$2 = /*@__PURE__*/ new Vector3();
7174 const _quaternion$2 = /*@__PURE__*/ new Quaternion();
7175
7176 const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );
7177 const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );
7178 const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );
7179
7180 const _addedEvent = { type: 'added' };
7181 const _removedEvent = { type: 'removed' };
7182
7183 class Object3D extends EventDispatcher {
7184
7185 constructor() {
7186
7187 super();
7188
7189 this.isObject3D = true;
7190
7191 Object.defineProperty( this, 'id', { value: _object3DId ++ } );
7192
7193 this.uuid = generateUUID();
7194
7195 this.name = '';
7196 this.type = 'Object3D';
7197
7198 this.parent = null;
7199 this.children = [];
7200
7201 this.up = Object3D.DEFAULT_UP.clone();
7202
7203 const position = new Vector3();
7204 const rotation = new Euler();
7205 const quaternion = new Quaternion();
7206 const scale = new Vector3( 1, 1, 1 );
7207
7208 function onRotationChange() {
7209
7210 quaternion.setFromEuler( rotation, false );
7211
7212 }
7213
7214 function onQuaternionChange() {
7215
7216 rotation.setFromQuaternion( quaternion, undefined, false );
7217
7218 }
7219
7220 rotation._onChange( onRotationChange );
7221 quaternion._onChange( onQuaternionChange );
7222
7223 Object.defineProperties( this, {
7224 position: {
7225 configurable: true,
7226 enumerable: true,
7228 },
7229 rotation: {
7230 configurable: true,
7231 enumerable: true,
7233 },
7234 quaternion: {
7235 configurable: true,
7236 enumerable: true,
7238 },
7239 scale: {
7240 configurable: true,
7241 enumerable: true,
7242 value: scale
7243 },
7245 value: new Matrix4()
7246 },
7247 normalMatrix: {
7248 value: new Matrix3()
7249 }
7250 } );
7251
7252 this.matrix = new Matrix4();
7253 this.matrixWorld = new Matrix4();
7254
7255 this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
7256
7257 this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer
7258 this.matrixWorldNeedsUpdate = false;
7259
7260 this.layers = new Layers();
7261 this.visible = true;
7262
7263 this.castShadow = false;
7264 this.receiveShadow = false;
7265
7266 this.frustumCulled = true;
7267 this.renderOrder = 0;
7268
7269 this.animations = [];
7270
7271 this.userData = {};
7272
7273 }
7274
7275 onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7276
7277 onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}
7278
7279 onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7280
7281 onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}
7282
7283 applyMatrix4( matrix ) {
7284
7285 if ( this.matrixAutoUpdate ) this.updateMatrix();
7286
7287 this.matrix.premultiply( matrix );
7288
7289 this.matrix.decompose( this.position, this.quaternion, this.scale );
7290
7291 }
7292
7293 applyQuaternion( q ) {
7294
7295 this.quaternion.premultiply( q );
7296
7297 return this;
7298
7299 }
7300
7301 setRotationFromAxisAngle( axis, angle ) {
7302
7303 // assumes axis is normalized
7304
7305 this.quaternion.setFromAxisAngle( axis, angle );
7306
7307 }
7308
7310
7311 this.quaternion.setFromEuler( euler, true );
7312
7313 }
7314
7316
7317 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
7318
7319 this.quaternion.setFromRotationMatrix( m );
7320
7321 }
7322
7324
7325 // assumes q is normalized
7326
7327 this.quaternion.copy( q );
7328
7329 }
7330
7331 rotateOnAxis( axis, angle ) {
7332
7333 // rotate object on axis in object space
7334 // axis is assumed to be normalized
7335
7336 _q1.setFromAxisAngle( axis, angle );
7337
7338 this.quaternion.multiply( _q1 );
7339
7340 return this;
7341
7342 }
7343
7344 rotateOnWorldAxis( axis, angle ) {
7345
7346 // rotate object on axis in world space
7347 // axis is assumed to be normalized
7348 // method assumes no rotated parent
7349
7350 _q1.setFromAxisAngle( axis, angle );
7351
7352 this.quaternion.premultiply( _q1 );
7353
7354 return this;
7355
7356 }
7357
7358 rotateX( angle ) {
7359
7360 return this.rotateOnAxis( _xAxis, angle );
7361
7362 }
7363
7364 rotateY( angle ) {
7365
7366 return this.rotateOnAxis( _yAxis, angle );
7367
7368 }
7369
7370 rotateZ( angle ) {
7371
7372 return this.rotateOnAxis( _zAxis, angle );
7373
7374 }
7375
7377
7378 // translate object by distance along axis in object space
7379 // axis is assumed to be normalized
7380
7381 _v1$4.copy( axis ).applyQuaternion( this.quaternion );
7382
7383 this.position.add( _v1$4.multiplyScalar( distance ) );
7384
7385 return this;
7386
7387 }
7388
7389 translateX( distance ) {
7390
7391 return this.translateOnAxis( _xAxis, distance );
7392
7393 }
7394
7395 translateY( distance ) {
7396
7397 return this.translateOnAxis( _yAxis, distance );
7398
7399 }
7400
7401 translateZ( distance ) {
7402
7403 return this.translateOnAxis( _zAxis, distance );
7404
7405 }
7406
7407 localToWorld( vector ) {
7408
7409 this.updateWorldMatrix( true, false );
7410
7411 return vector.applyMatrix4( this.matrixWorld );
7412
7413 }
7414
7415 worldToLocal( vector ) {
7416
7417 this.updateWorldMatrix( true, false );
7418
7419 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() );
7420
7421 }
7422
7423 lookAt( x, y, z ) {
7424
7425 // This method does not support objects having non-uniformly-scaled parent(s)
7426
7427 if ( x.isVector3 ) {
7428
7429 _target.copy( x );
7430
7431 } else {
7432
7433 _target.set( x, y, z );
7434
7435 }
7436
7437 const parent = this.parent;
7438
7439 this.updateWorldMatrix( true, false );
7440
7441 _position$3.setFromMatrixPosition( this.matrixWorld );
7442
7443 if ( this.isCamera || this.isLight ) {
7444
7445 _m1$1.lookAt( _position$3, _target, this.up );
7446
7447 } else {
7448
7449 _m1$1.lookAt( _target, _position$3, this.up );
7450
7451 }
7452
7453 this.quaternion.setFromRotationMatrix( _m1$1 );
7454
7455 if ( parent ) {
7456
7457 _m1$1.extractRotation( parent.matrixWorld );
7458 _q1.setFromRotationMatrix( _m1$1 );
7459 this.quaternion.premultiply( _q1.invert() );
7460
7461 }
7462
7463 }
7464
7465 add( object ) {
7466
7467 if ( arguments.length > 1 ) {
7468
7469 for ( let i = 0; i < arguments.length; i ++ ) {
7470
7471 this.add( arguments[ i ] );
7472
7473 }
7474
7475 return this;
7476
7477 }
7478
7479 if ( object === this ) {
7480
7481 console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object );
7482 return this;
7483
7484 }
7485
7486 if ( object && object.isObject3D ) {
7487
7488 if ( object.parent !== null ) {
7489
7490 object.parent.remove( object );
7491
7492 }
7493
7494 object.parent = this;
7495 this.children.push( object );
7496
7497 object.dispatchEvent( _addedEvent );
7498
7499 } else {
7500
7501 console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );
7502
7503 }
7504
7505 return this;
7506
7507 }
7508
7509 remove( object ) {
7510
7511 if ( arguments.length > 1 ) {
7512
7513 for ( let i = 0; i < arguments.length; i ++ ) {
7514
7515 this.remove( arguments[ i ] );
7516
7517 }
7518
7519 return this;
7520
7521 }
7522
7523 const index = this.children.indexOf( object );
7524
7525 if ( index !== - 1 ) {
7526
7527 object.parent = null;
7528 this.children.splice( index, 1 );
7529
7530 object.dispatchEvent( _removedEvent );
7531
7532 }
7533
7534 return this;
7535
7536 }
7537
7539
7540 const parent = this.parent;
7541
7542 if ( parent !== null ) {
7543
7544 parent.remove( this );
7545
7546 }
7547
7548 return this;
7549
7550 }
7551
7552 clear() {
7553
7554 return this.remove( ... this.children );
7555
7556 }
7557
7558 attach( object ) {
7559
7560 // adds object as a child of this, while maintaining the object's world transform
7561
7562 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)
7563
7564 this.updateWorldMatrix( true, false );
7565
7566 _m1$1.copy( this.matrixWorld ).invert();
7567
7568 if ( object.parent !== null ) {
7569
7570 object.parent.updateWorldMatrix( true, false );
7571
7572 _m1$1.multiply( object.parent.matrixWorld );
7573
7574 }
7575
7576 object.applyMatrix4( _m1$1 );
7577
7578 this.add( object );
7579
7580 object.updateWorldMatrix( false, true );
7581
7582 return this;
7583
7584 }
7585
7586 getObjectById( id ) {
7587
7588 return this.getObjectByProperty( 'id', id );
7589
7590 }
7591
7593
7594 return this.getObjectByProperty( 'name', name );
7595
7596 }
7597
7599
7600 if ( this[ name ] === value ) return this;
7601
7602 for ( let i = 0, l = this.children.length; i < l; i ++ ) {
7603
7604 const child = this.children[ i ];
7605 const object = child.getObjectByProperty( name, value );
7606
7607 if ( object !== undefined ) {
7608
7609 return object;
7610
7611 }
7612
7613 }
7614
7615 return undefined;
7616
7617 }
7618
7620
7621 if ( this[ name ] === value ) result.push( this );
7622
7623 const children = this.children;
7624
7625 for ( let i = 0, l = children.length; i < l; i ++ ) {
7626
7627 children[ i ].getObjectsByProperty( name, value, result );
7628
7629 }
7630
7631 return result;
7632
7633 }
7634
7636
7637 this.updateWorldMatrix( true, false );
7638
7639 return target.setFromMatrixPosition( this.matrixWorld );
7640
7641 }
7642
7644
7645 this.updateWorldMatrix( true, false );
7646
7647 this.matrixWorld.decompose( _position$3, target, _scale$2 );
7648
7649 return target;
7650
7651 }
7652
7654
7655 this.updateWorldMatrix( true, false );
7656
7657 this.matrixWorld.decompose( _position$3, _quaternion$2, target );
7658
7659 return target;
7660
7661 }
7662
7664
7665 this.updateWorldMatrix( true, false );
7666
7667 const e = this.matrixWorld.elements;
7668
7669 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();
7670
7671 }
7672
7673 raycast( /* raycaster, intersects */ ) {}
7674
7675 traverse( callback ) {
7676
7677 callback( this );
7678
7679 const children = this.children;
7680
7681 for ( let i = 0, l = children.length; i < l; i ++ ) {
7682
7683 children[ i ].traverse( callback );
7684
7685 }
7686
7687 }
7688
7690
7691 if ( this.visible === false ) return;
7692
7693 callback( this );
7694
7695 const children = this.children;
7696
7697 for ( let i = 0, l = children.length; i < l; i ++ ) {
7698
7699 children[ i ].traverseVisible( callback );
7700
7701 }
7702
7703 }
7704
7706
7707 const parent = this.parent;
7708
7709 if ( parent !== null ) {
7710
7711 callback( parent );
7712
7713 parent.traverseAncestors( callback );
7714
7715 }
7716
7717 }
7718
7719 updateMatrix() {
7720
7721 this.matrix.compose( this.position, this.quaternion, this.scale );
7722
7723 this.matrixWorldNeedsUpdate = true;
7724
7725 }
7726
7728
7729 if ( this.matrixAutoUpdate ) this.updateMatrix();
7730
7731 if ( this.matrixWorldNeedsUpdate || force ) {
7732
7733 if ( this.parent === null ) {
7734
7735 this.matrixWorld.copy( this.matrix );
7736
7737 } else {
7738
7739 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7740
7741 }
7742
7743 this.matrixWorldNeedsUpdate = false;
7744
7745 force = true;
7746
7747 }
7748
7749 // update children
7750
7751 const children = this.children;
7752
7753 for ( let i = 0, l = children.length; i < l; i ++ ) {
7754
7755 const child = children[ i ];
7756
7757 if ( child.matrixWorldAutoUpdate === true || force === true ) {
7758
7759 child.updateMatrixWorld( force );
7760
7761 }
7762
7763 }
7764
7765 }
7766
7768
7769 const parent = this.parent;
7770
7771 if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) {
7772
7773 parent.updateWorldMatrix( true, false );
7774
7775 }
7776
7777 if ( this.matrixAutoUpdate ) this.updateMatrix();
7778
7779 if ( this.parent === null ) {
7780
7781 this.matrixWorld.copy( this.matrix );
7782
7783 } else {
7784
7785 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
7786
7787 }
7788
7789 // update children
7790
7791 if ( updateChildren === true ) {
7792
7793 const children = this.children;
7794
7795 for ( let i = 0, l = children.length; i < l; i ++ ) {
7796
7797 const child = children[ i ];
7798
7799 if ( child.matrixWorldAutoUpdate === true ) {
7800
7801 child.updateWorldMatrix( false, true );
7802
7803 }
7804
7805 }
7806
7807 }
7808
7809 }
7810
7811 toJSON( meta ) {
7812
7813 // meta is a string when called from JSON.stringify
7814 const isRootObject = ( meta === undefined || typeof meta === 'string' );
7815
7816 const output = {};
7817
7818 // meta is a hash used to collect geometries, materials.
7819 // not providing it implies that this is the root object
7820 // being serialized.
7821 if ( isRootObject ) {
7822
7823 // initialize meta obj
7824 meta = {
7825 geometries: {},
7826 materials: {},
7827 textures: {},
7828 images: {},
7829 shapes: {},
7830 skeletons: {},
7831 animations: {},
7832 nodes: {}
7833 };
7834
7835 output.metadata = {
7836 version: 4.6,
7837 type: 'Object',
7838 generator: 'Object3D.toJSON'
7839 };
7840
7841 }
7842
7843 // standard Object3D serialization
7844
7845 const object = {};
7846
7847 object.uuid = this.uuid;
7848 object.type = this.type;
7849
7850 if ( this.name !== '' ) object.name = this.name;
7851 if ( this.castShadow === true ) object.castShadow = true;
7852 if ( this.receiveShadow === true ) object.receiveShadow = true;
7853 if ( this.visible === false ) object.visible = false;
7854 if ( this.frustumCulled === false ) object.frustumCulled = false;
7855 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;
7856 if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;
7857
7858 object.layers = this.layers.mask;
7859 object.matrix = this.matrix.toArray();
7860 object.up = this.up.toArray();
7861
7862 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;
7863
7864 // object specific properties
7865
7866 if ( this.isInstancedMesh ) {
7867
7868 object.type = 'InstancedMesh';
7869 object.count = this.count;
7870 object.instanceMatrix = this.instanceMatrix.toJSON();
7871 if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();
7872
7873 }
7874
7875 if ( this.isBatchedMesh ) {
7876
7877 object.type = 'BatchedMesh';
7878 object.perObjectFrustumCulled = this.perObjectFrustumCulled;
7879 object.sortObjects = this.sortObjects;
7880
7881 object.drawRanges = this._drawRanges;
7882 object.reservedRanges = this._reservedRanges;
7883
7884 object.visibility = this._visibility;
7885 object.active = this._active;
7886 object.bounds = this._bounds.map( bound => ( {
7887 boxInitialized: bound.boxInitialized,
7888 boxMin: bound.box.min.toArray(),
7889 boxMax: bound.box.max.toArray(),
7890
7894 } ) );
7895
7896 object.maxGeometryCount = this._maxGeometryCount;
7897 object.maxVertexCount = this._maxVertexCount;
7898 object.maxIndexCount = this._maxIndexCount;
7899
7900 object.geometryInitialized = this._geometryInitialized;
7901 object.geometryCount = this._geometryCount;
7902
7903 object.matricesTexture = this._matricesTexture.toJSON( meta );
7904
7905 if ( this.boundingSphere !== null ) {
7906
7907 object.boundingSphere = {
7908 center: object.boundingSphere.center.toArray(),
7909 radius: object.boundingSphere.radius
7910 };
7911
7912 }
7913
7914 if ( this.boundingBox !== null ) {
7915
7916 object.boundingBox = {
7917 min: object.boundingBox.min.toArray(),
7918 max: object.boundingBox.max.toArray()
7919 };
7920
7921 }
7922
7923 }
7924
7925 //
7926
7927 function serialize( library, element ) {
7928
7929 if ( library[ element.uuid ] === undefined ) {
7930
7931 library[ element.uuid ] = element.toJSON( meta );
7932
7933 }
7934
7935 return element.uuid;
7936
7937 }
7938
7939 if ( this.isScene ) {
7940
7941 if ( this.background ) {
7942
7943 if ( this.background.isColor ) {
7944
7945 object.background = this.background.toJSON();
7946
7947 } else if ( this.background.isTexture ) {
7948
7949 object.background = this.background.toJSON( meta ).uuid;
7950
7951 }
7952
7953 }
7954
7955 if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {
7956
7957 object.environment = this.environment.toJSON( meta ).uuid;
7958
7959 }
7960
7961 } else if ( this.isMesh || this.isLine || this.isPoints ) {
7962
7963 object.geometry = serialize( meta.geometries, this.geometry );
7964
7965 const parameters = this.geometry.parameters;
7966
7967 if ( parameters !== undefined && parameters.shapes !== undefined ) {
7968
7969 const shapes = parameters.shapes;
7970
7971 if ( Array.isArray( shapes ) ) {
7972
7973 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
7974
7975 const shape = shapes[ i ];
7976
7977 serialize( meta.shapes, shape );
7978
7979 }
7980
7981 } else {
7982
7983 serialize( meta.shapes, shapes );
7984
7985 }
7986
7987 }
7988
7989 }
7990
7991 if ( this.isSkinnedMesh ) {
7992
7993 object.bindMode = this.bindMode;
7994 object.bindMatrix = this.bindMatrix.toArray();
7995
7996 if ( this.skeleton !== undefined ) {
7997
7998 serialize( meta.skeletons, this.skeleton );
7999
8000 object.skeleton = this.skeleton.uuid;
8001
8002 }
8003
8004 }
8005
8006 if ( this.material !== undefined ) {
8007
8008 if ( Array.isArray( this.material ) ) {
8009
8010 const uuids = [];
8011
8012 for ( let i = 0, l = this.material.length; i < l; i ++ ) {
8013
8014 uuids.push( serialize( meta.materials, this.material[ i ] ) );
8015
8016 }
8017
8018 object.material = uuids;
8019
8020 } else {
8021
8022 object.material = serialize( meta.materials, this.material );
8023
8024 }
8025
8026 }
8027
8028 //
8029
8030 if ( this.children.length > 0 ) {
8031
8032 object.children = [];
8033
8034 for ( let i = 0; i < this.children.length; i ++ ) {
8035
8036 object.children.push( this.children[ i ].toJSON( meta ).object );
8037
8038 }
8039
8040 }
8041
8042 //
8043
8044 if ( this.animations.length > 0 ) {
8045
8046 object.animations = [];
8047
8048 for ( let i = 0; i < this.animations.length; i ++ ) {
8049
8050 const animation = this.animations[ i ];
8051
8052 object.animations.push( serialize( meta.animations, animation ) );
8053
8054 }
8055
8056 }
8057
8058 if ( isRootObject ) {
8059
8060 const geometries = extractFromCache( meta.geometries );
8061 const materials = extractFromCache( meta.materials );
8062 const textures = extractFromCache( meta.textures );
8063 const images = extractFromCache( meta.images );
8064 const shapes = extractFromCache( meta.shapes );
8065 const skeletons = extractFromCache( meta.skeletons );
8066 const animations = extractFromCache( meta.animations );
8067 const nodes = extractFromCache( meta.nodes );
8068
8069 if ( geometries.length > 0 ) output.geometries = geometries;
8070 if ( materials.length > 0 ) output.materials = materials;
8071 if ( textures.length > 0 ) output.textures = textures;
8072 if ( images.length > 0 ) output.images = images;
8073 if ( shapes.length > 0 ) output.shapes = shapes;
8074 if ( skeletons.length > 0 ) output.skeletons = skeletons;
8075 if ( animations.length > 0 ) output.animations = animations;
8076 if ( nodes.length > 0 ) output.nodes = nodes;
8077
8078 }
8079
8080 output.object = object;
8081
8082 return output;
8083
8084 // extract data from the cache hash
8085 // remove metadata on each item
8086 // and return as array
8087 function extractFromCache( cache ) {
8088
8089 const values = [];
8090 for ( const key in cache ) {
8091
8092 const data = cache[ key ];
8093 delete data.metadata;
8094 values.push( data );
8095
8096 }
8097
8098 return values;
8099
8100 }
8101
8102 }
8103
8104 clone( recursive ) {
8105
8106 return new this.constructor().copy( this, recursive );
8107
8108 }
8109
8110 copy( source, recursive = true ) {
8111
8112 this.name = source.name;
8113
8114 this.up.copy( source.up );
8115
8116 this.position.copy( source.position );
8117 this.rotation.order = source.rotation.order;
8118 this.quaternion.copy( source.quaternion );
8119 this.scale.copy( source.scale );
8120
8121 this.matrix.copy( source.matrix );
8122 this.matrixWorld.copy( source.matrixWorld );
8123
8124 this.matrixAutoUpdate = source.matrixAutoUpdate;
8125
8126 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
8127 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
8128
8129 this.layers.mask = source.layers.mask;
8130 this.visible = source.visible;
8131
8132 this.castShadow = source.castShadow;
8133 this.receiveShadow = source.receiveShadow;
8134
8135 this.frustumCulled = source.frustumCulled;
8136 this.renderOrder = source.renderOrder;
8137
8138 this.animations = source.animations.slice();
8139
8140 this.userData = JSON.parse( JSON.stringify( source.userData ) );
8141
8142 if ( recursive === true ) {
8143
8144 for ( let i = 0; i < source.children.length; i ++ ) {
8145
8146 const child = source.children[ i ];
8147 this.add( child.clone() );
8148
8149 }
8150
8151 }
8152
8153 return this;
8154
8155 }
8156
8157 }
8158
8159 Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );
8160 Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true;
8161 Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;
8162
8163 const _v0$1 = /*@__PURE__*/ new Vector3();
8164 const _v1$3 = /*@__PURE__*/ new Vector3();
8165 const _v2$2 = /*@__PURE__*/ new Vector3();
8166 const _v3$1 = /*@__PURE__*/ new Vector3();
8167
8168 const _vab = /*@__PURE__*/ new Vector3();
8169 const _vac = /*@__PURE__*/ new Vector3();
8170 const _vbc = /*@__PURE__*/ new Vector3();
8171 const _vap = /*@__PURE__*/ new Vector3();
8172 const _vbp = /*@__PURE__*/ new Vector3();
8173 const _vcp = /*@__PURE__*/ new Vector3();
8174
8175 let warnedGetUV = false;
8176
8177 class Triangle {
8178
8179 constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
8180
8181 this.a = a;
8182 this.b = b;
8183 this.c = c;
8184
8185 }
8186
8187 static getNormal( a, b, c, target ) {
8188
8189 target.subVectors( c, b );
8190 _v0$1.subVectors( a, b );
8191 target.cross( _v0$1 );
8192
8193 const targetLengthSq = target.lengthSq();
8194 if ( targetLengthSq > 0 ) {
8195
8196 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
8197
8198 }
8199
8200 return target.set( 0, 0, 0 );
8201
8202 }
8203
8204 // static/instance method to calculate barycentric coordinates
8205 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
8206 static getBarycoord( point, a, b, c, target ) {
8207
8208 _v0$1.subVectors( c, a );
8209 _v1$3.subVectors( b, a );
8210 _v2$2.subVectors( point, a );
8211
8212 const dot00 = _v0$1.dot( _v0$1 );
8213 const dot01 = _v0$1.dot( _v1$3 );
8214 const dot02 = _v0$1.dot( _v2$2 );
8215 const dot11 = _v1$3.dot( _v1$3 );
8216 const dot12 = _v1$3.dot( _v2$2 );
8217
8218 const denom = ( dot00 * dot11 - dot01 * dot01 );
8219
8220 // collinear or singular triangle
8221 if ( denom === 0 ) {
8222
8223 target.set( 0, 0, 0 );
8224 return null;
8225
8226 }
8227
8228 const invDenom = 1 / denom;
8229 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
8230 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
8231
8232 // barycentric coordinates must always sum to 1
8233 return target.set( 1 - u - v, v, u );
8234
8235 }
8236
8237 static containsPoint( point, a, b, c ) {
8238
8239 // if the triangle is degenerate then we can't contain a point
8240 if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) {
8241
8242 return false;
8243
8244 }
8245
8246 return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 );
8247
8248 }
8249
8250 static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151
8251
8252 if ( warnedGetUV === false ) {
8253
8254 console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8255
8256 warnedGetUV = true;
8257
8258 }
8259
8260 return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target );
8261
8262 }
8263
8264 static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
8265
8266 if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) {
8267
8268 target.x = 0;
8269 target.y = 0;
8270 if ( 'z' in target ) target.z = 0;
8271 if ( 'w' in target ) target.w = 0;
8272 return null;
8273
8274 }
8275
8276 target.setScalar( 0 );
8277 target.addScaledVector( v1, _v3$1.x );
8278 target.addScaledVector( v2, _v3$1.y );
8279 target.addScaledVector( v3, _v3$1.z );
8280
8281 return target;
8282
8283 }
8284
8285 static isFrontFacing( a, b, c, direction ) {
8286
8287 _v0$1.subVectors( c, b );
8288 _v1$3.subVectors( a, b );
8289
8290 // strictly front facing
8291 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;
8292
8293 }
8294
8295 set( a, b, c ) {
8296
8297 this.a.copy( a );
8298 this.b.copy( b );
8299 this.c.copy( c );
8300
8301 return this;
8302
8303 }
8304
8306
8307 this.a.copy( points[ i0 ] );
8308 this.b.copy( points[ i1 ] );
8309 this.c.copy( points[ i2 ] );
8310
8311 return this;
8312
8313 }
8314
8316
8317 this.a.fromBufferAttribute( attribute, i0 );
8318 this.b.fromBufferAttribute( attribute, i1 );
8319 this.c.fromBufferAttribute( attribute, i2 );
8320
8321 return this;
8322
8323 }
8324
8325 clone() {
8326
8327 return new this.constructor().copy( this );
8328
8329 }
8330
8331 copy( triangle ) {
8332
8333 this.a.copy( triangle.a );
8334 this.b.copy( triangle.b );
8335 this.c.copy( triangle.c );
8336
8337 return this;
8338
8339 }
8340
8341 getArea() {
8342
8343 _v0$1.subVectors( this.c, this.b );
8344 _v1$3.subVectors( this.a, this.b );
8345
8346 return _v0$1.cross( _v1$3 ).length() * 0.5;
8347
8348 }
8349
8350 getMidpoint( target ) {
8351
8352 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
8353
8354 }
8355
8356 getNormal( target ) {
8357
8358 return Triangle.getNormal( this.a, this.b, this.c, target );
8359
8360 }
8361
8362 getPlane( target ) {
8363
8364 return target.setFromCoplanarPoints( this.a, this.b, this.c );
8365
8366 }
8367
8369
8370 return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
8371
8372 }
8373
8374 getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151
8375
8376 if ( warnedGetUV === false ) {
8377
8378 console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' );
8379
8380 warnedGetUV = true;
8381
8382 }
8383
8384 return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
8385
8386 }
8387
8389
8390 return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );
8391
8392 }
8393
8394 containsPoint( point ) {
8395
8396 return Triangle.containsPoint( point, this.a, this.b, this.c );
8397
8398 }
8399
8401
8402 return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
8403
8404 }
8405
8406 intersectsBox( box ) {
8407
8408 return box.intersectsTriangle( this );
8409
8410 }
8411
8413
8414 const a = this.a, b = this.b, c = this.c;
8415 let v, w;
8416
8417 // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
8418 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
8419 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
8420 // basically, we're distinguishing which of the voronoi regions of the triangle
8421 // the point lies in with the minimum amount of redundant computation.
8422
8423 _vab.subVectors( b, a );
8424 _vac.subVectors( c, a );
8425 _vap.subVectors( p, a );
8426 const d1 = _vab.dot( _vap );
8427 const d2 = _vac.dot( _vap );
8428 if ( d1 <= 0 && d2 <= 0 ) {
8429
8430 // vertex region of A; barycentric coords (1, 0, 0)
8431 return target.copy( a );
8432
8433 }
8434
8435 _vbp.subVectors( p, b );
8436 const d3 = _vab.dot( _vbp );
8437 const d4 = _vac.dot( _vbp );
8438 if ( d3 >= 0 && d4 <= d3 ) {
8439
8440 // vertex region of B; barycentric coords (0, 1, 0)
8441 return target.copy( b );
8442
8443 }
8444
8445 const vc = d1 * d4 - d3 * d2;
8446 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
8447
8448 v = d1 / ( d1 - d3 );
8449 // edge region of AB; barycentric coords (1-v, v, 0)
8450 return target.copy( a ).addScaledVector( _vab, v );
8451
8452 }
8453
8454 _vcp.subVectors( p, c );
8455 const d5 = _vab.dot( _vcp );
8456 const d6 = _vac.dot( _vcp );
8457 if ( d6 >= 0 && d5 <= d6 ) {
8458
8459 // vertex region of C; barycentric coords (0, 0, 1)
8460 return target.copy( c );
8461
8462 }
8463
8464 const vb = d5 * d2 - d1 * d6;
8465 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
8466
8467 w = d2 / ( d2 - d6 );
8468 // edge region of AC; barycentric coords (1-w, 0, w)
8469 return target.copy( a ).addScaledVector( _vac, w );
8470
8471 }
8472
8473 const va = d3 * d6 - d5 * d4;
8474 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
8475
8476 _vbc.subVectors( c, b );
8477 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
8478 // edge region of BC; barycentric coords (0, 1-w, w)
8479 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
8480
8481 }
8482
8483 // face region
8484 const denom = 1 / ( va + vb + vc );
8485 // u = va * denom
8486 v = vb * denom;
8487 w = vc * denom;
8488
8489 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
8490
8491 }
8492
8493 equals( triangle ) {
8494
8495 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
8496
8497 }
8498
8499 }
8500
8501 const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
8502 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
8503 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
8504 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
8505 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
8506 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
8507 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
8508 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
8509 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
8510 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
8511 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
8512 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
8513 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
8514 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
8515 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
8516 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
8517 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
8518 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
8519 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
8520 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
8521 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
8522 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
8523 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
8524 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
8525
8526 const _hslA = { h: 0, s: 0, l: 0 };
8527 const _hslB = { h: 0, s: 0, l: 0 };
8528
8529 function hue2rgb( p, q, t ) {
8530
8531 if ( t < 0 ) t += 1;
8532 if ( t > 1 ) t -= 1;
8533 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
8534 if ( t < 1 / 2 ) return q;
8535 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
8536 return p;
8537
8538 }
8539
8540 class Color {
8541
8542 constructor( r, g, b ) {
8543
8544 this.isColor = true;
8545
8546 this.r = 1;
8547 this.g = 1;
8548 this.b = 1;
8549
8550 return this.set( r, g, b );
8551
8552 }
8553
8554 set( r, g, b ) {
8555
8556 if ( g === undefined && b === undefined ) {
8557
8558 // r is THREE.Color, hex or string
8559
8560 const value = r;
8561
8562 if ( value && value.isColor ) {
8563
8564 this.copy( value );
8565
8566 } else if ( typeof value === 'number' ) {
8567
8568 this.setHex( value );
8569
8570 } else if ( typeof value === 'string' ) {
8571
8572 this.setStyle( value );
8573
8574 }
8575
8576 } else {
8577
8578 this.setRGB( r, g, b );
8579
8580 }
8581
8582 return this;
8583
8584 }
8585
8586 setScalar( scalar ) {
8587
8588 this.r = scalar;
8589 this.g = scalar;
8590 this.b = scalar;
8591
8592 return this;
8593
8594 }
8595
8596 setHex( hex, colorSpace = SRGBColorSpace ) {
8597
8598 hex = Math.floor( hex );
8599
8600 this.r = ( hex >> 16 & 255 ) / 255;
8601 this.g = ( hex >> 8 & 255 ) / 255;
8602 this.b = ( hex & 255 ) / 255;
8603
8604 ColorManagement.toWorkingColorSpace( this, colorSpace );
8605
8606 return this;
8607
8608 }
8609
8610 setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {
8611
8612 this.r = r;
8613 this.g = g;
8614 this.b = b;
8615
8616 ColorManagement.toWorkingColorSpace( this, colorSpace );
8617
8618 return this;
8619
8620 }
8621
8622 setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {
8623
8624 // h,s,l ranges are in 0.0 - 1.0
8625 h = euclideanModulo( h, 1 );
8626 s = clamp( s, 0, 1 );
8627 l = clamp( l, 0, 1 );
8628
8629 if ( s === 0 ) {
8630
8631 this.r = this.g = this.b = l;
8632
8633 } else {
8634
8635 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
8636 const q = ( 2 * l ) - p;
8637
8638 this.r = hue2rgb( q, p, h + 1 / 3 );
8639 this.g = hue2rgb( q, p, h );
8640 this.b = hue2rgb( q, p, h - 1 / 3 );
8641
8642 }
8643
8644 ColorManagement.toWorkingColorSpace( this, colorSpace );
8645
8646 return this;
8647
8648 }
8649
8651
8652 function handleAlpha( string ) {
8653
8654 if ( string === undefined ) return;
8655
8656 if ( parseFloat( string ) < 1 ) {
8657
8658 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
8659
8660 }
8661
8662 }
8663
8664
8665 let m;
8666
8667 if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) {
8668
8669 // rgb / hsl
8670
8671 let color;
8672 const name = m[ 1 ];
8673 const components = m[ 2 ];
8674
8675 switch ( name ) {
8676
8677 case 'rgb':
8678 case 'rgba':
8679
8680 if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8681
8682 // rgb(255,0,0) rgba(255,0,0,0.5)
8683
8684 handleAlpha( color[ 4 ] );
8685
8686 return this.setRGB(
8687 Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,
8688 Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,
8689 Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,
8691 );
8692
8693 }
8694
8695 if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8696
8697 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
8698
8699 handleAlpha( color[ 4 ] );
8700
8701 return this.setRGB(
8702 Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,
8703 Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,
8704 Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,
8706 );
8707
8708 }
8709
8710 break;
8711
8712 case 'hsl':
8713 case 'hsla':
8714
8715 if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
8716
8717 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
8718
8719 handleAlpha( color[ 4 ] );
8720
8721 return this.setHSL(
8722 parseFloat( color[ 1 ] ) / 360,
8723 parseFloat( color[ 2 ] ) / 100,
8724 parseFloat( color[ 3 ] ) / 100,
8726 );
8727
8728 }
8729
8730 break;
8731
8732 default:
8733
8734 console.warn( 'THREE.Color: Unknown color model ' + style );
8735
8736 }
8737
8738 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) {
8739
8740 // hex color
8741
8742 const hex = m[ 1 ];
8743 const size = hex.length;
8744
8745 if ( size === 3 ) {
8746
8747 // #ff0
8748 return this.setRGB(
8749 parseInt( hex.charAt( 0 ), 16 ) / 15,
8750 parseInt( hex.charAt( 1 ), 16 ) / 15,
8751 parseInt( hex.charAt( 2 ), 16 ) / 15,
8753 );
8754
8755 } else if ( size === 6 ) {
8756
8757 // #ff0000
8758 return this.setHex( parseInt( hex, 16 ), colorSpace );
8759
8760 } else {
8761
8762 console.warn( 'THREE.Color: Invalid hex color ' + style );
8763
8764 }
8765
8766 } else if ( style && style.length > 0 ) {
8767
8768 return this.setColorName( style, colorSpace );
8769
8770 }
8771
8772 return this;
8773
8774 }
8775
8777
8778 // color keywords
8779 const hex = _colorKeywords[ style.toLowerCase() ];
8780
8781 if ( hex !== undefined ) {
8782
8783 // red
8784 this.setHex( hex, colorSpace );
8785
8786 } else {
8787
8788 // unknown color
8789 console.warn( 'THREE.Color: Unknown color ' + style );
8790
8791 }
8792
8793 return this;
8794
8795 }
8796
8797 clone() {
8798
8799 return new this.constructor( this.r, this.g, this.b );
8800
8801 }
8802
8803 copy( color ) {
8804
8805 this.r = color.r;
8806 this.g = color.g;
8807 this.b = color.b;
8808
8809 return this;
8810
8811 }
8812
8814
8815 this.r = SRGBToLinear( color.r );
8816 this.g = SRGBToLinear( color.g );
8817 this.b = SRGBToLinear( color.b );
8818
8819 return this;
8820
8821 }
8822
8824
8825 this.r = LinearToSRGB( color.r );
8826 this.g = LinearToSRGB( color.g );
8827 this.b = LinearToSRGB( color.b );
8828
8829 return this;
8830
8831 }
8832
8834
8835 this.copySRGBToLinear( this );
8836
8837 return this;
8838
8839 }
8840
8842
8843 this.copyLinearToSRGB( this );
8844
8845 return this;
8846
8847 }
8848
8850
8851 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8852
8853 return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) );
8854
8855 }
8856
8858
8859 return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );
8860
8861 }
8862
8863 getHSL( target, colorSpace = ColorManagement.workingColorSpace ) {
8864
8865 // h,s,l ranges are in 0.0 - 1.0
8866
8867 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8868
8869 const r = _color.r, g = _color.g, b = _color.b;
8870
8871 const max = Math.max( r, g, b );
8872 const min = Math.min( r, g, b );
8873
8875 const lightness = ( min + max ) / 2.0;
8876
8877 if ( min === max ) {
8878
8879 hue = 0;
8880 saturation = 0;
8881
8882 } else {
8883
8884 const delta = max - min;
8885
8886 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
8887
8888 switch ( max ) {
8889
8890 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
8891 case g: hue = ( b - r ) / delta + 2; break;
8892 case b: hue = ( r - g ) / delta + 4; break;
8893
8894 }
8895
8896 hue /= 6;
8897
8898 }
8899
8900 target.h = hue;
8901 target.s = saturation;
8902 target.l = lightness;
8903
8904 return target;
8905
8906 }
8907
8908 getRGB( target, colorSpace = ColorManagement.workingColorSpace ) {
8909
8910 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8911
8912 target.r = _color.r;
8913 target.g = _color.g;
8914 target.b = _color.b;
8915
8916 return target;
8917
8918 }
8919
8921
8922 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );
8923
8924 const r = _color.r, g = _color.g, b = _color.b;
8925
8926 if ( colorSpace !== SRGBColorSpace ) {
8927
8928 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).
8929 return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;
8930
8931 }
8932
8933 return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;
8934
8935 }
8936
8937 offsetHSL( h, s, l ) {
8938
8939 this.getHSL( _hslA );
8940
8941 return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );
8942
8943 }
8944
8945 add( color ) {
8946
8947 this.r += color.r;
8948 this.g += color.g;
8949 this.b += color.b;
8950
8951 return this;
8952
8953 }
8954
8955 addColors( color1, color2 ) {
8956
8957 this.r = color1.r + color2.r;
8958 this.g = color1.g + color2.g;
8959 this.b = color1.b + color2.b;
8960
8961 return this;
8962
8963 }
8964
8965 addScalar( s ) {
8966
8967 this.r += s;
8968 this.g += s;
8969 this.b += s;
8970
8971 return this;
8972
8973 }
8974
8975 sub( color ) {
8976
8977 this.r = Math.max( 0, this.r - color.r );
8978 this.g = Math.max( 0, this.g - color.g );
8979 this.b = Math.max( 0, this.b - color.b );
8980
8981 return this;
8982
8983 }
8984
8985 multiply( color ) {
8986
8987 this.r *= color.r;
8988 this.g *= color.g;
8989 this.b *= color.b;
8990
8991 return this;
8992
8993 }
8994
8995 multiplyScalar( s ) {
8996
8997 this.r *= s;
8998 this.g *= s;
8999 this.b *= s;
9000
9001 return this;
9002
9003 }
9004
9005 lerp( color, alpha ) {
9006
9007 this.r += ( color.r - this.r ) * alpha;
9008 this.g += ( color.g - this.g ) * alpha;
9009 this.b += ( color.b - this.b ) * alpha;
9010
9011 return this;
9012
9013 }
9014
9016
9017 this.r = color1.r + ( color2.r - color1.r ) * alpha;
9018 this.g = color1.g + ( color2.g - color1.g ) * alpha;
9019 this.b = color1.b + ( color2.b - color1.b ) * alpha;
9020
9021 return this;
9022
9023 }
9024
9025 lerpHSL( color, alpha ) {
9026
9027 this.getHSL( _hslA );
9028 color.getHSL( _hslB );
9029
9030 const h = lerp( _hslA.h, _hslB.h, alpha );
9031 const s = lerp( _hslA.s, _hslB.s, alpha );
9032 const l = lerp( _hslA.l, _hslB.l, alpha );
9033
9034 this.setHSL( h, s, l );
9035
9036 return this;
9037
9038 }
9039
9040 setFromVector3( v ) {
9041
9042 this.r = v.x;
9043 this.g = v.y;
9044 this.b = v.z;
9045
9046 return this;
9047
9048 }
9049
9050 applyMatrix3( m ) {
9051
9052 const r = this.r, g = this.g, b = this.b;
9053 const e = m.elements;
9054
9055 this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;
9056 this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;
9057 this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;
9058
9059 return this;
9060
9061 }
9062
9063 equals( c ) {
9064
9065 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
9066
9067 }
9068
9069 fromArray( array, offset = 0 ) {
9070
9071 this.r = array[ offset ];
9072 this.g = array[ offset + 1 ];
9073 this.b = array[ offset + 2 ];
9074
9075 return this;
9076
9077 }
9078
9079 toArray( array = [], offset = 0 ) {
9080
9081 array[ offset ] = this.r;
9082 array[ offset + 1 ] = this.g;
9083 array[ offset + 2 ] = this.b;
9084
9085 return array;
9086
9087 }
9088
9090
9091 this.r = attribute.getX( index );
9092 this.g = attribute.getY( index );
9093 this.b = attribute.getZ( index );
9094
9095 return this;
9096
9097 }
9098
9099 toJSON() {
9100
9101 return this.getHex();
9102
9103 }
9104
9105 *[ Symbol.iterator ]() {
9106
9107 yield this.r;
9108 yield this.g;
9109 yield this.b;
9110
9111 }
9112
9113 }
9114
9115 const _color = /*@__PURE__*/ new Color();
9116
9117 Color.NAMES = _colorKeywords;
9118
9119 let _materialId = 0;
9120
9121 class Material extends EventDispatcher {
9122
9123 constructor() {
9124
9125 super();
9126
9127 this.isMaterial = true;
9128
9129 Object.defineProperty( this, 'id', { value: _materialId ++ } );
9130
9131 this.uuid = generateUUID();
9132
9133 this.name = '';
9134 this.type = 'Material';
9135
9136 this.blending = NormalBlending;
9137 this.side = FrontSide;
9138 this.vertexColors = false;
9139
9140 this.opacity = 1;
9141 this.transparent = false;
9142 this.alphaHash = false;
9143
9144 this.blendSrc = SrcAlphaFactor;
9147 this.blendSrcAlpha = null;
9148 this.blendDstAlpha = null;
9149 this.blendEquationAlpha = null;
9150 this.blendColor = new Color( 0, 0, 0 );
9151 this.blendAlpha = 0;
9152
9154 this.depthTest = true;
9155 this.depthWrite = true;
9156
9157 this.stencilWriteMask = 0xff;
9159 this.stencilRef = 0;
9160 this.stencilFuncMask = 0xff;
9164 this.stencilWrite = false;
9165
9166 this.clippingPlanes = null;
9167 this.clipIntersection = false;
9168 this.clipShadows = false;
9169
9170 this.shadowSide = null;
9171
9172 this.colorWrite = true;
9173
9174 this.precision = null; // override the renderer's default precision for this material
9175
9176 this.polygonOffset = false;
9177 this.polygonOffsetFactor = 0;
9178 this.polygonOffsetUnits = 0;
9179
9180 this.dithering = false;
9181
9182 this.alphaToCoverage = false;
9183 this.premultipliedAlpha = false;
9184 this.forceSinglePass = false;
9185
9186 this.visible = true;
9187
9188 this.toneMapped = true;
9189
9190 this.userData = {};
9191
9192 this.version = 0;
9193
9194 this._alphaTest = 0;
9195
9196 }
9197
9198 get alphaTest() {
9199
9200 return this._alphaTest;
9201
9202 }
9203
9204 set alphaTest( value ) {
9205
9206 if ( this._alphaTest > 0 !== value > 0 ) {
9207
9208 this.version ++;
9209
9210 }
9211
9212 this._alphaTest = value;
9213
9214 }
9215
9216 onBuild( /* shaderobject, renderer */ ) {}
9217
9218 onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
9219
9220 onBeforeCompile( /* shaderobject, renderer */ ) {}
9221
9223
9224 return this.onBeforeCompile.toString();
9225
9226 }
9227
9228 setValues( values ) {
9229
9230 if ( values === undefined ) return;
9231
9232 for ( const key in values ) {
9233
9234 const newValue = values[ key ];
9235
9236 if ( newValue === undefined ) {
9237
9238 console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );
9239 continue;
9240
9241 }
9242
9243 const currentValue = this[ key ];
9244
9245 if ( currentValue === undefined ) {
9246
9247 console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );
9248 continue;
9249
9250 }
9251
9252 if ( currentValue && currentValue.isColor ) {
9253
9254 currentValue.set( newValue );
9255
9256 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
9257
9258 currentValue.copy( newValue );
9259
9260 } else {
9261
9262 this[ key ] = newValue;
9263
9264 }
9265
9266 }
9267
9268 }
9269
9270 toJSON( meta ) {
9271
9272 const isRootObject = ( meta === undefined || typeof meta === 'string' );
9273
9274 if ( isRootObject ) {
9275
9276 meta = {
9277 textures: {},
9278 images: {}
9279 };
9280
9281 }
9282
9283 const data = {
9284 metadata: {
9285 version: 4.6,
9286 type: 'Material',
9287 generator: 'Material.toJSON'
9288 }
9289 };
9290
9291 // standard Material serialization
9292 data.uuid = this.uuid;
9293 data.type = this.type;
9294
9295 if ( this.name !== '' ) data.name = this.name;
9296
9297 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
9298
9299 if ( this.roughness !== undefined ) data.roughness = this.roughness;
9300 if ( this.metalness !== undefined ) data.metalness = this.metalness;
9301
9302 if ( this.sheen !== undefined ) data.sheen = this.sheen;
9303 if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
9304 if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
9305 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
9306 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
9307
9308 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
9309 if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
9310 if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
9311 if ( this.shininess !== undefined ) data.shininess = this.shininess;
9312 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
9313 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
9314
9315 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
9316
9317 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
9318
9319 }
9320
9321 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
9322
9323 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
9324
9325 }
9326
9327 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
9328
9329 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
9330 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
9331
9332 }
9333
9334 if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
9335 if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
9336 if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
9337
9338 if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
9339
9340 data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
9341
9342 }
9343
9344 if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
9345
9346 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
9347
9348 }
9349
9350 if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
9351 if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
9352
9353 if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
9354
9355 data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
9356
9357 }
9358
9359 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
9360 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
9361 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
9362
9363 if ( this.lightMap && this.lightMap.isTexture ) {
9364
9365 data.lightMap = this.lightMap.toJSON( meta ).uuid;
9366 data.lightMapIntensity = this.lightMapIntensity;
9367
9368 }
9369
9370 if ( this.aoMap && this.aoMap.isTexture ) {
9371
9372 data.aoMap = this.aoMap.toJSON( meta ).uuid;
9373 data.aoMapIntensity = this.aoMapIntensity;
9374
9375 }
9376
9377 if ( this.bumpMap && this.bumpMap.isTexture ) {
9378
9379 data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
9380 data.bumpScale = this.bumpScale;
9381
9382 }
9383
9384 if ( this.normalMap && this.normalMap.isTexture ) {
9385
9386 data.normalMap = this.normalMap.toJSON( meta ).uuid;
9387 data.normalMapType = this.normalMapType;
9388 data.normalScale = this.normalScale.toArray();
9389
9390 }
9391
9392 if ( this.displacementMap && this.displacementMap.isTexture ) {
9393
9394 data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
9395 data.displacementScale = this.displacementScale;
9396 data.displacementBias = this.displacementBias;
9397
9398 }
9399
9400 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
9401 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
9402
9403 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
9404 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
9405 if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
9406 if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
9407
9408 if ( this.envMap && this.envMap.isTexture ) {
9409
9410 data.envMap = this.envMap.toJSON( meta ).uuid;
9411
9412 if ( this.combine !== undefined ) data.combine = this.combine;
9413
9414 }
9415
9416 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
9417 if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
9418 if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
9419
9420 if ( this.gradientMap && this.gradientMap.isTexture ) {
9421
9422 data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
9423
9424 }
9425
9426 if ( this.transmission !== undefined ) data.transmission = this.transmission;
9427 if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
9428 if ( this.thickness !== undefined ) data.thickness = this.thickness;
9429 if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
9430 if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
9431 if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
9432
9433 if ( this.size !== undefined ) data.size = this.size;
9434 if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
9435 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
9436
9437 if ( this.blending !== NormalBlending ) data.blending = this.blending;
9438 if ( this.side !== FrontSide ) data.side = this.side;
9439 if ( this.vertexColors === true ) data.vertexColors = true;
9440
9441 if ( this.opacity < 1 ) data.opacity = this.opacity;
9442 if ( this.transparent === true ) data.transparent = true;
9443
9444 if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
9445 if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
9446 if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
9447 if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
9448 if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
9449 if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
9450 if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
9451 if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
9452
9453 if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
9454 if ( this.depthTest === false ) data.depthTest = this.depthTest;
9455 if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
9456 if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
9457
9458 if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
9459 if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
9460 if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
9461 if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
9462 if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
9463 if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
9464 if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
9465 if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
9466
9467 // rotation (SpriteMaterial)
9468 if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
9469
9470 if ( this.polygonOffset === true ) data.polygonOffset = true;
9471 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
9472 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
9473
9474 if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
9475 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
9476 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
9477 if ( this.scale !== undefined ) data.scale = this.scale;
9478
9479 if ( this.dithering === true ) data.dithering = true;
9480
9481 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
9482 if ( this.alphaHash === true ) data.alphaHash = true;
9483 if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
9484 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
9485 if ( this.forceSinglePass === true ) data.forceSinglePass = true;
9486
9487 if ( this.wireframe === true ) data.wireframe = true;
9488 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
9489 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
9490 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
9491
9492 if ( this.flatShading === true ) data.flatShading = true;
9493
9494 if ( this.visible === false ) data.visible = false;
9495
9496 if ( this.toneMapped === false ) data.toneMapped = false;
9497
9498 if ( this.fog === false ) data.fog = false;
9499
9500 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
9501
9502 // TODO: Copied from Object3D.toJSON
9503
9504 function extractFromCache( cache ) {
9505
9506 const values = [];
9507
9508 for ( const key in cache ) {
9509
9510 const data = cache[ key ];
9511 delete data.metadata;
9512 values.push( data );
9513
9514 }
9515
9516 return values;
9517
9518 }
9519
9520 if ( isRootObject ) {
9521
9522 const textures = extractFromCache( meta.textures );
9523 const images = extractFromCache( meta.images );
9524
9525 if ( textures.length > 0 ) data.textures = textures;
9526 if ( images.length > 0 ) data.images = images;
9527
9528 }
9529
9530 return data;
9531
9532 }
9533
9534 clone() {
9535
9536 return new this.constructor().copy( this );
9537
9538 }
9539
9540 copy( source ) {
9541
9542 this.name = source.name;
9543
9544 this.blending = source.blending;
9545 this.side = source.side;
9546 this.vertexColors = source.vertexColors;
9547
9548 this.opacity = source.opacity;
9549 this.transparent = source.transparent;
9550
9551 this.blendSrc = source.blendSrc;
9552 this.blendDst = source.blendDst;
9553 this.blendEquation = source.blendEquation;
9554 this.blendSrcAlpha = source.blendSrcAlpha;
9555 this.blendDstAlpha = source.blendDstAlpha;
9556 this.blendEquationAlpha = source.blendEquationAlpha;
9557 this.blendColor.copy( source.blendColor );
9558 this.blendAlpha = source.blendAlpha;
9559
9560 this.depthFunc = source.depthFunc;
9561 this.depthTest = source.depthTest;
9562 this.depthWrite = source.depthWrite;
9563
9564 this.stencilWriteMask = source.stencilWriteMask;
9565 this.stencilFunc = source.stencilFunc;
9566 this.stencilRef = source.stencilRef;
9567 this.stencilFuncMask = source.stencilFuncMask;
9568 this.stencilFail = source.stencilFail;
9569 this.stencilZFail = source.stencilZFail;
9570 this.stencilZPass = source.stencilZPass;
9571 this.stencilWrite = source.stencilWrite;
9572
9573 const srcPlanes = source.clippingPlanes;
9574 let dstPlanes = null;
9575
9576 if ( srcPlanes !== null ) {
9577
9578 const n = srcPlanes.length;
9579 dstPlanes = new Array( n );
9580
9581 for ( let i = 0; i !== n; ++ i ) {
9582
9583 dstPlanes[ i ] = srcPlanes[ i ].clone();
9584
9585 }
9586
9587 }
9588
9590 this.clipIntersection = source.clipIntersection;
9591 this.clipShadows = source.clipShadows;
9592
9593 this.shadowSide = source.shadowSide;
9594
9595 this.colorWrite = source.colorWrite;
9596
9597 this.precision = source.precision;
9598
9599 this.polygonOffset = source.polygonOffset;
9600 this.polygonOffsetFactor = source.polygonOffsetFactor;
9601 this.polygonOffsetUnits = source.polygonOffsetUnits;
9602
9603 this.dithering = source.dithering;
9604
9605 this.alphaTest = source.alphaTest;
9606 this.alphaHash = source.alphaHash;
9607 this.alphaToCoverage = source.alphaToCoverage;
9608 this.premultipliedAlpha = source.premultipliedAlpha;
9609 this.forceSinglePass = source.forceSinglePass;
9610
9611 this.visible = source.visible;
9612
9613 this.toneMapped = source.toneMapped;
9614
9615 this.userData = JSON.parse( JSON.stringify( source.userData ) );
9616
9617 return this;
9618
9619 }
9620
9621 dispose() {
9622
9623 this.dispatchEvent( { type: 'dispose' } );
9624
9625 }
9626
9627 set needsUpdate( value ) {
9628
9629 if ( value === true ) this.version ++;
9630
9631 }
9632
9633 }
9634
9635 class MeshBasicMaterial extends Material {
9636
9638
9639 super();
9640
9641 this.isMeshBasicMaterial = true;
9642
9643 this.type = 'MeshBasicMaterial';
9644
9645 this.color = new Color( 0xffffff ); // emissive
9646
9647 this.map = null;
9648
9649 this.lightMap = null;
9650 this.lightMapIntensity = 1.0;
9651
9652 this.aoMap = null;
9653 this.aoMapIntensity = 1.0;
9654
9655 this.specularMap = null;
9656
9657 this.alphaMap = null;
9658
9659 this.envMap = null;
9661 this.reflectivity = 1;
9662 this.refractionRatio = 0.98;
9663
9664 this.wireframe = false;
9665 this.wireframeLinewidth = 1;
9666 this.wireframeLinecap = 'round';
9667 this.wireframeLinejoin = 'round';
9668
9669 this.fog = true;
9670
9671 this.setValues( parameters );
9672
9673 }
9674
9675 copy( source ) {
9676
9677 super.copy( source );
9678
9679 this.color.copy( source.color );
9680
9681 this.map = source.map;
9682
9683 this.lightMap = source.lightMap;
9684 this.lightMapIntensity = source.lightMapIntensity;
9685
9686 this.aoMap = source.aoMap;
9687 this.aoMapIntensity = source.aoMapIntensity;
9688
9689 this.specularMap = source.specularMap;
9690
9691 this.alphaMap = source.alphaMap;
9692
9693 this.envMap = source.envMap;
9694 this.combine = source.combine;
9695 this.reflectivity = source.reflectivity;
9696 this.refractionRatio = source.refractionRatio;
9697
9698 this.wireframe = source.wireframe;
9699 this.wireframeLinewidth = source.wireframeLinewidth;
9700 this.wireframeLinecap = source.wireframeLinecap;
9701 this.wireframeLinejoin = source.wireframeLinejoin;
9702
9703 this.fog = source.fog;
9704
9705 return this;
9706
9707 }
9708
9709 }
9710
9711 // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
9712
9713 const _tables = /*@__PURE__*/ _generateTables();
9714
9715 function _generateTables() {
9716
9717 // float32 to float16 helpers
9718
9719 const buffer = new ArrayBuffer( 4 );
9720 const floatView = new Float32Array( buffer );
9721 const uint32View = new Uint32Array( buffer );
9722
9723 const baseTable = new Uint32Array( 512 );
9724 const shiftTable = new Uint32Array( 512 );
9725
9726 for ( let i = 0; i < 256; ++ i ) {
9727
9728 const e = i - 127;
9729
9730 // very small number (0, -0)
9731
9732 if ( e < - 27 ) {
9733
9734 baseTable[ i ] = 0x0000;
9735 baseTable[ i | 0x100 ] = 0x8000;
9736 shiftTable[ i ] = 24;
9737 shiftTable[ i | 0x100 ] = 24;
9738
9739 // small number (denorm)
9740
9741 } else if ( e < - 14 ) {
9742
9743 baseTable[ i ] = 0x0400 >> ( - e - 14 );
9744 baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;
9745 shiftTable[ i ] = - e - 1;
9746 shiftTable[ i | 0x100 ] = - e - 1;
9747
9748 // normal number
9749
9750 } else if ( e <= 15 ) {
9751
9752 baseTable[ i ] = ( e + 15 ) << 10;
9753 baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;
9754 shiftTable[ i ] = 13;
9755 shiftTable[ i | 0x100 ] = 13;
9756
9757 // large number (Infinity, -Infinity)
9758
9759 } else if ( e < 128 ) {
9760
9761 baseTable[ i ] = 0x7c00;
9762 baseTable[ i | 0x100 ] = 0xfc00;
9763 shiftTable[ i ] = 24;
9764 shiftTable[ i | 0x100 ] = 24;
9765
9766 // stay (NaN, Infinity, -Infinity)
9767
9768 } else {
9769
9770 baseTable[ i ] = 0x7c00;
9771 baseTable[ i | 0x100 ] = 0xfc00;
9772 shiftTable[ i ] = 13;
9773 shiftTable[ i | 0x100 ] = 13;
9774
9775 }
9776
9777 }
9778
9779 // float16 to float32 helpers
9780
9781 const mantissaTable = new Uint32Array( 2048 );
9782 const exponentTable = new Uint32Array( 64 );
9783 const offsetTable = new Uint32Array( 64 );
9784
9785 for ( let i = 1; i < 1024; ++ i ) {
9786
9787 let m = i << 13; // zero pad mantissa bits
9788 let e = 0; // zero exponent
9789
9790 // normalized
9791 while ( ( m & 0x00800000 ) === 0 ) {
9792
9793 m <<= 1;
9794 e -= 0x00800000; // decrement exponent
9795
9796 }
9797
9798 m &= ~ 0x00800000; // clear leading 1 bit
9799 e += 0x38800000; // adjust bias
9800
9801 mantissaTable[ i ] = m | e;
9802
9803 }
9804
9805 for ( let i = 1024; i < 2048; ++ i ) {
9806
9807 mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );
9808
9809 }
9810
9811 for ( let i = 1; i < 31; ++ i ) {
9812
9813 exponentTable[ i ] = i << 23;
9814
9815 }
9816
9817 exponentTable[ 31 ] = 0x47800000;
9818 exponentTable[ 32 ] = 0x80000000;
9819
9820 for ( let i = 33; i < 63; ++ i ) {
9821
9822 exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );
9823
9824 }
9825
9826 exponentTable[ 63 ] = 0xc7800000;
9827
9828 for ( let i = 1; i < 64; ++ i ) {
9829
9830 if ( i !== 32 ) {
9831
9832 offsetTable[ i ] = 1024;
9833
9834 }
9835
9836 }
9837
9838 return {
9846 };
9847
9848 }
9849
9850 // float32 to float16
9851
9852 function toHalfFloat( val ) {
9853
9854 if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );
9855
9856 val = clamp( val, - 65504, 65504 );
9857
9858 _tables.floatView[ 0 ] = val;
9859 const f = _tables.uint32View[ 0 ];
9860 const e = ( f >> 23 ) & 0x1ff;
9861 return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );
9862
9863 }
9864
9865 // float16 to float32
9866
9867 function fromHalfFloat( val ) {
9868
9869 const m = val >> 10;
9870 _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];
9871 return _tables.floatView[ 0 ];
9872
9873 }
9874
9875 const DataUtils = {
9878 };
9879
9880 const _vector$9 = /*@__PURE__*/ new Vector3();
9881 const _vector2$1 = /*@__PURE__*/ new Vector2();
9882
9883 class BufferAttribute {
9884
9885 constructor( array, itemSize, normalized = false ) {
9886
9887 if ( Array.isArray( array ) ) {
9888
9889 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
9890
9891 }
9892
9893 this.isBufferAttribute = true;
9894
9895 this.name = '';
9896
9897 this.array = array;
9898 this.itemSize = itemSize;
9899 this.count = array !== undefined ? array.length / itemSize : 0;
9900 this.normalized = normalized;
9901
9902 this.usage = StaticDrawUsage;
9903 this._updateRange = { offset: 0, count: - 1 };
9904 this.updateRanges = [];
9905 this.gpuType = FloatType;
9906
9907 this.version = 0;
9908
9909 }
9910
9911 onUploadCallback() {}
9912
9913 set needsUpdate( value ) {
9914
9915 if ( value === true ) this.version ++;
9916
9917 }
9918
9919 get updateRange() {
9920
9921 console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
9922 return this._updateRange;
9923
9924 }
9925
9926 setUsage( value ) {
9927
9928 this.usage = value;
9929
9930 return this;
9931
9932 }
9933
9934 addUpdateRange( start, count ) {
9935
9936 this.updateRanges.push( { start, count } );
9937
9938 }
9939
9941
9942 this.updateRanges.length = 0;
9943
9944 }
9945
9946 copy( source ) {
9947
9948 this.name = source.name;
9949 this.array = new source.array.constructor( source.array );
9950 this.itemSize = source.itemSize;
9951 this.count = source.count;
9952 this.normalized = source.normalized;
9953
9954 this.usage = source.usage;
9955 this.gpuType = source.gpuType;
9956
9957 return this;
9958
9959 }
9960
9962
9963 index1 *= this.itemSize;
9964 index2 *= attribute.itemSize;
9965
9966 for ( let i = 0, l = this.itemSize; i < l; i ++ ) {
9967
9968 this.array[ index1 + i ] = attribute.array[ index2 + i ];
9969
9970 }
9971
9972 return this;
9973
9974 }
9975
9976 copyArray( array ) {
9977
9978 this.array.set( array );
9979
9980 return this;
9981
9982 }
9983
9984 applyMatrix3( m ) {
9985
9986 if ( this.itemSize === 2 ) {
9987
9988 for ( let i = 0, l = this.count; i < l; i ++ ) {
9989
9990 _vector2$1.fromBufferAttribute( this, i );
9991 _vector2$1.applyMatrix3( m );
9992
9993 this.setXY( i, _vector2$1.x, _vector2$1.y );
9994
9995 }
9996
9997 } else if ( this.itemSize === 3 ) {
9998
9999 for ( let i = 0, l = this.count; i < l; i ++ ) {
10000
10001 _vector$9.fromBufferAttribute( this, i );
10002 _vector$9.applyMatrix3( m );
10003
10004 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10005
10006 }
10007
10008 }
10009
10010 return this;
10011
10012 }
10013
10014 applyMatrix4( m ) {
10015
10016 for ( let i = 0, l = this.count; i < l; i ++ ) {
10017
10018 _vector$9.fromBufferAttribute( this, i );
10019
10020 _vector$9.applyMatrix4( m );
10021
10022 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10023
10024 }
10025
10026 return this;
10027
10028 }
10029
10030 applyNormalMatrix( m ) {
10031
10032 for ( let i = 0, l = this.count; i < l; i ++ ) {
10033
10034 _vector$9.fromBufferAttribute( this, i );
10035
10036 _vector$9.applyNormalMatrix( m );
10037
10038 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10039
10040 }
10041
10042 return this;
10043
10044 }
10045
10046 transformDirection( m ) {
10047
10048 for ( let i = 0, l = this.count; i < l; i ++ ) {
10049
10050 _vector$9.fromBufferAttribute( this, i );
10051
10052 _vector$9.transformDirection( m );
10053
10054 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );
10055
10056 }
10057
10058 return this;
10059
10060 }
10061
10062 set( value, offset = 0 ) {
10063
10064 // Matching BufferAttribute constructor, do not normalize the array.
10065 this.array.set( value, offset );
10066
10067 return this;
10068
10069 }
10070
10072
10073 let value = this.array[ index * this.itemSize + component ];
10074
10075 if ( this.normalized ) value = denormalize( value, this.array );
10076
10077 return value;
10078
10079 }
10080
10081 setComponent( index, component, value ) {
10082
10083 if ( this.normalized ) value = normalize( value, this.array );
10084
10085 this.array[ index * this.itemSize + component ] = value;
10086
10087 return this;
10088
10089 }
10090
10091 getX( index ) {
10092
10093 let x = this.array[ index * this.itemSize ];
10094
10095 if ( this.normalized ) x = denormalize( x, this.array );
10096
10097 return x;
10098
10099 }
10100
10101 setX( index, x ) {
10102
10103 if ( this.normalized ) x = normalize( x, this.array );
10104
10105 this.array[ index * this.itemSize ] = x;
10106
10107 return this;
10108
10109 }
10110
10111 getY( index ) {
10112
10113 let y = this.array[ index * this.itemSize + 1 ];
10114
10115 if ( this.normalized ) y = denormalize( y, this.array );
10116
10117 return y;
10118
10119 }
10120
10121 setY( index, y ) {
10122
10123 if ( this.normalized ) y = normalize( y, this.array );
10124
10125 this.array[ index * this.itemSize + 1 ] = y;
10126
10127 return this;
10128
10129 }
10130
10131 getZ( index ) {
10132
10133 let z = this.array[ index * this.itemSize + 2 ];
10134
10135 if ( this.normalized ) z = denormalize( z, this.array );
10136
10137 return z;
10138
10139 }
10140
10141 setZ( index, z ) {
10142
10143 if ( this.normalized ) z = normalize( z, this.array );
10144
10145 this.array[ index * this.itemSize + 2 ] = z;
10146
10147 return this;
10148
10149 }
10150
10151 getW( index ) {
10152
10153 let w = this.array[ index * this.itemSize + 3 ];
10154
10155 if ( this.normalized ) w = denormalize( w, this.array );
10156
10157 return w;
10158
10159 }
10160
10161 setW( index, w ) {
10162
10163 if ( this.normalized ) w = normalize( w, this.array );
10164
10165 this.array[ index * this.itemSize + 3 ] = w;
10166
10167 return this;
10168
10169 }
10170
10171 setXY( index, x, y ) {
10172
10173 index *= this.itemSize;
10174
10175 if ( this.normalized ) {
10176
10177 x = normalize( x, this.array );
10178 y = normalize( y, this.array );
10179
10180 }
10181
10182 this.array[ index + 0 ] = x;
10183 this.array[ index + 1 ] = y;
10184
10185 return this;
10186
10187 }
10188
10189 setXYZ( index, x, y, z ) {
10190
10191 index *= this.itemSize;
10192
10193 if ( this.normalized ) {
10194
10195 x = normalize( x, this.array );
10196 y = normalize( y, this.array );
10197 z = normalize( z, this.array );
10198
10199 }
10200
10201 this.array[ index + 0 ] = x;
10202 this.array[ index + 1 ] = y;
10203 this.array[ index + 2 ] = z;
10204
10205 return this;
10206
10207 }
10208
10209 setXYZW( index, x, y, z, w ) {
10210
10211 index *= this.itemSize;
10212
10213 if ( this.normalized ) {
10214
10215 x = normalize( x, this.array );
10216 y = normalize( y, this.array );
10217 z = normalize( z, this.array );
10218 w = normalize( w, this.array );
10219
10220 }
10221
10222 this.array[ index + 0 ] = x;
10223 this.array[ index + 1 ] = y;
10224 this.array[ index + 2 ] = z;
10225 this.array[ index + 3 ] = w;
10226
10227 return this;
10228
10229 }
10230
10231 onUpload( callback ) {
10232
10234
10235 return this;
10236
10237 }
10238
10239 clone() {
10240
10241 return new this.constructor( this.array, this.itemSize ).copy( this );
10242
10243 }
10244
10245 toJSON() {
10246
10247 const data = {
10248 itemSize: this.itemSize,
10249 type: this.array.constructor.name,
10250 array: Array.from( this.array ),
10252 };
10253
10254 if ( this.name !== '' ) data.name = this.name;
10255 if ( this.usage !== StaticDrawUsage ) data.usage = this.usage;
10256
10257 return data;
10258
10259 }
10260
10261 }
10262
10263 //
10264
10265 class Int8BufferAttribute extends BufferAttribute {
10266
10268
10270
10271 }
10272
10273 }
10274
10276
10278
10280
10281 }
10282
10283 }
10284
10286
10288
10290
10291 }
10292
10293 }
10294
10296
10298
10300
10301 }
10302
10303 }
10304
10306
10308
10310
10311 }
10312
10313 }
10314
10316
10318
10320
10321 }
10322
10323 }
10324
10326
10328
10330
10331 }
10332
10333 }
10334
10336
10338
10340
10341 this.isFloat16BufferAttribute = true;
10342
10343 }
10344
10345 getX( index ) {
10346
10347 let x = fromHalfFloat( this.array[ index * this.itemSize ] );
10348
10349 if ( this.normalized ) x = denormalize( x, this.array );
10350
10351 return x;
10352
10353 }
10354
10355 setX( index, x ) {
10356
10357 if ( this.normalized ) x = normalize( x, this.array );
10358
10359 this.array[ index * this.itemSize ] = toHalfFloat( x );
10360
10361 return this;
10362
10363 }
10364
10365 getY( index ) {
10366
10367 let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );
10368
10369 if ( this.normalized ) y = denormalize( y, this.array );
10370
10371 return y;
10372
10373 }
10374
10375 setY( index, y ) {
10376
10377 if ( this.normalized ) y = normalize( y, this.array );
10378
10379 this.array[ index * this.itemSize + 1 ] = toHalfFloat( y );
10380
10381 return this;
10382
10383 }
10384
10385 getZ( index ) {
10386
10387 let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );
10388
10389 if ( this.normalized ) z = denormalize( z, this.array );
10390
10391 return z;
10392
10393 }
10394
10395 setZ( index, z ) {
10396
10397 if ( this.normalized ) z = normalize( z, this.array );
10398
10399 this.array[ index * this.itemSize + 2 ] = toHalfFloat( z );
10400
10401 return this;
10402
10403 }
10404
10405 getW( index ) {
10406
10407 let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );
10408
10409 if ( this.normalized ) w = denormalize( w, this.array );
10410
10411 return w;
10412
10413 }
10414
10415 setW( index, w ) {
10416
10417 if ( this.normalized ) w = normalize( w, this.array );
10418
10419 this.array[ index * this.itemSize + 3 ] = toHalfFloat( w );
10420
10421 return this;
10422
10423 }
10424
10425 setXY( index, x, y ) {
10426
10427 index *= this.itemSize;
10428
10429 if ( this.normalized ) {
10430
10431 x = normalize( x, this.array );
10432 y = normalize( y, this.array );
10433
10434 }
10435
10436 this.array[ index + 0 ] = toHalfFloat( x );
10437 this.array[ index + 1 ] = toHalfFloat( y );
10438
10439 return this;
10440
10441 }
10442
10443 setXYZ( index, x, y, z ) {
10444
10445 index *= this.itemSize;
10446
10447 if ( this.normalized ) {
10448
10449 x = normalize( x, this.array );
10450 y = normalize( y, this.array );
10451 z = normalize( z, this.array );
10452
10453 }
10454
10455 this.array[ index + 0 ] = toHalfFloat( x );
10456 this.array[ index + 1 ] = toHalfFloat( y );
10457 this.array[ index + 2 ] = toHalfFloat( z );
10458
10459 return this;
10460
10461 }
10462
10463 setXYZW( index, x, y, z, w ) {
10464
10465 index *= this.itemSize;
10466
10467 if ( this.normalized ) {
10468
10469 x = normalize( x, this.array );
10470 y = normalize( y, this.array );
10471 z = normalize( z, this.array );
10472 w = normalize( w, this.array );
10473
10474 }
10475
10476 this.array[ index + 0 ] = toHalfFloat( x );
10477 this.array[ index + 1 ] = toHalfFloat( y );
10478 this.array[ index + 2 ] = toHalfFloat( z );
10479 this.array[ index + 3 ] = toHalfFloat( w );
10480
10481 return this;
10482
10483 }
10484
10485 }
10486
10487
10489
10491
10493
10494 }
10495
10496 }
10497
10499
10501
10503
10504 }
10505
10506 }
10507
10508 let _id$2 = 0;
10509
10510 const _m1 = /*@__PURE__*/ new Matrix4();
10511 const _obj = /*@__PURE__*/ new Object3D();
10512 const _offset = /*@__PURE__*/ new Vector3();
10513 const _box$2 = /*@__PURE__*/ new Box3();
10514 const _boxMorphTargets = /*@__PURE__*/ new Box3();
10515 const _vector$8 = /*@__PURE__*/ new Vector3();
10516
10517 class BufferGeometry extends EventDispatcher {
10518
10519 constructor() {
10520
10521 super();
10522
10523 this.isBufferGeometry = true;
10524
10525 Object.defineProperty( this, 'id', { value: _id$2 ++ } );
10526
10527 this.uuid = generateUUID();
10528
10529 this.name = '';
10530 this.type = 'BufferGeometry';
10531
10532 this.index = null;
10533 this.attributes = {};
10534
10535 this.morphAttributes = {};
10536 this.morphTargetsRelative = false;
10537
10538 this.groups = [];
10539
10540 this.boundingBox = null;
10541 this.boundingSphere = null;
10542
10543 this.drawRange = { start: 0, count: Infinity };
10544
10545 this.userData = {};
10546
10547 }
10548
10549 getIndex() {
10550
10551 return this.index;
10552
10553 }
10554
10555 setIndex( index ) {
10556
10557 if ( Array.isArray( index ) ) {
10558
10560
10561 } else {
10562
10563 this.index = index;
10564
10565 }
10566
10567 return this;
10568
10569 }
10570
10571 getAttribute( name ) {
10572
10573 return this.attributes[ name ];
10574
10575 }
10576
10578
10579 this.attributes[ name ] = attribute;
10580
10581 return this;
10582
10583 }
10584
10586
10587 delete this.attributes[ name ];
10588
10589 return this;
10590
10591 }
10592
10593 hasAttribute( name ) {
10594
10595 return this.attributes[ name ] !== undefined;
10596
10597 }
10598
10599 addGroup( start, count, materialIndex = 0 ) {
10600
10601 this.groups.push( {
10602
10603 start: start,
10604 count: count,
10606
10607 } );
10608
10609 }
10610
10611 clearGroups() {
10612
10613 this.groups = [];
10614
10615 }
10616
10617 setDrawRange( start, count ) {
10618
10619 this.drawRange.start = start;
10620 this.drawRange.count = count;
10621
10622 }
10623
10624 applyMatrix4( matrix ) {
10625
10626 const position = this.attributes.position;
10627
10628 if ( position !== undefined ) {
10629
10630 position.applyMatrix4( matrix );
10631
10632 position.needsUpdate = true;
10633
10634 }
10635
10636 const normal = this.attributes.normal;
10637
10638 if ( normal !== undefined ) {
10639
10640 const normalMatrix = new Matrix3().getNormalMatrix( matrix );
10641
10642 normal.applyNormalMatrix( normalMatrix );
10643
10644 normal.needsUpdate = true;
10645
10646 }
10647
10648 const tangent = this.attributes.tangent;
10649
10650 if ( tangent !== undefined ) {
10651
10652 tangent.transformDirection( matrix );
10653
10654 tangent.needsUpdate = true;
10655
10656 }
10657
10658 if ( this.boundingBox !== null ) {
10659
10660 this.computeBoundingBox();
10661
10662 }
10663
10664 if ( this.boundingSphere !== null ) {
10665
10666 this.computeBoundingSphere();
10667
10668 }
10669
10670 return this;
10671
10672 }
10673
10674 applyQuaternion( q ) {
10675
10676 _m1.makeRotationFromQuaternion( q );
10677
10678 this.applyMatrix4( _m1 );
10679
10680 return this;
10681
10682 }
10683
10684 rotateX( angle ) {
10685
10686 // rotate geometry around world x-axis
10687
10688 _m1.makeRotationX( angle );
10689
10690 this.applyMatrix4( _m1 );
10691
10692 return this;
10693
10694 }
10695
10696 rotateY( angle ) {
10697
10698 // rotate geometry around world y-axis
10699
10700 _m1.makeRotationY( angle );
10701
10702 this.applyMatrix4( _m1 );
10703
10704 return this;
10705
10706 }
10707
10708 rotateZ( angle ) {
10709
10710 // rotate geometry around world z-axis
10711
10712 _m1.makeRotationZ( angle );
10713
10714 this.applyMatrix4( _m1 );
10715
10716 return this;
10717
10718 }
10719
10720 translate( x, y, z ) {
10721
10722 // translate geometry
10723
10724 _m1.makeTranslation( x, y, z );
10725
10726 this.applyMatrix4( _m1 );
10727
10728 return this;
10729
10730 }
10731
10732 scale( x, y, z ) {
10733
10734 // scale geometry
10735
10736 _m1.makeScale( x, y, z );
10737
10738 this.applyMatrix4( _m1 );
10739
10740 return this;
10741
10742 }
10743
10744 lookAt( vector ) {
10745
10746 _obj.lookAt( vector );
10747
10748 _obj.updateMatrix();
10749
10750 this.applyMatrix4( _obj.matrix );
10751
10752 return this;
10753
10754 }
10755
10756 center() {
10757
10758 this.computeBoundingBox();
10759
10760 this.boundingBox.getCenter( _offset ).negate();
10761
10762 this.translate( _offset.x, _offset.y, _offset.z );
10763
10764 return this;
10765
10766 }
10767
10769
10770 const position = [];
10771
10772 for ( let i = 0, l = points.length; i < l; i ++ ) {
10773
10774 const point = points[ i ];
10775 position.push( point.x, point.y, point.z || 0 );
10776
10777 }
10778
10779 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
10780
10781 return this;
10782
10783 }
10784
10786
10787 if ( this.boundingBox === null ) {
10788
10789 this.boundingBox = new Box3();
10790
10791 }
10792
10793 const position = this.attributes.position;
10794 const morphAttributesPosition = this.morphAttributes.position;
10795
10796 if ( position && position.isGLBufferAttribute ) {
10797
10798 console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this );
10799
10800 this.boundingBox.set(
10801 new Vector3( - Infinity, - Infinity, - Infinity ),
10802 new Vector3( + Infinity, + Infinity, + Infinity )
10803 );
10804
10805 return;
10806
10807 }
10808
10809 if ( position !== undefined ) {
10810
10811 this.boundingBox.setFromBufferAttribute( position );
10812
10813 // process morph attributes if present
10814
10816
10817 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10818
10820 _box$2.setFromBufferAttribute( morphAttribute );
10821
10822 if ( this.morphTargetsRelative ) {
10823
10824 _vector$8.addVectors( this.boundingBox.min, _box$2.min );
10825 this.boundingBox.expandByPoint( _vector$8 );
10826
10827 _vector$8.addVectors( this.boundingBox.max, _box$2.max );
10828 this.boundingBox.expandByPoint( _vector$8 );
10829
10830 } else {
10831
10832 this.boundingBox.expandByPoint( _box$2.min );
10833 this.boundingBox.expandByPoint( _box$2.max );
10834
10835 }
10836
10837 }
10838
10839 }
10840
10841 } else {
10842
10843 this.boundingBox.makeEmpty();
10844
10845 }
10846
10847 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
10848
10849 console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
10850
10851 }
10852
10853 }
10854
10856
10857 if ( this.boundingSphere === null ) {
10858
10859 this.boundingSphere = new Sphere();
10860
10861 }
10862
10863 const position = this.attributes.position;
10864 const morphAttributesPosition = this.morphAttributes.position;
10865
10866 if ( position && position.isGLBufferAttribute ) {
10867
10868 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this );
10869
10870 this.boundingSphere.set( new Vector3(), Infinity );
10871
10872 return;
10873
10874 }
10875
10876 if ( position ) {
10877
10878 // first, find the center of the bounding sphere
10879
10880 const center = this.boundingSphere.center;
10881
10882 _box$2.setFromBufferAttribute( position );
10883
10884 // process morph attributes if present
10885
10887
10888 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10889
10891 _boxMorphTargets.setFromBufferAttribute( morphAttribute );
10892
10893 if ( this.morphTargetsRelative ) {
10894
10895 _vector$8.addVectors( _box$2.min, _boxMorphTargets.min );
10896 _box$2.expandByPoint( _vector$8 );
10897
10898 _vector$8.addVectors( _box$2.max, _boxMorphTargets.max );
10899 _box$2.expandByPoint( _vector$8 );
10900
10901 } else {
10902
10903 _box$2.expandByPoint( _boxMorphTargets.min );
10904 _box$2.expandByPoint( _boxMorphTargets.max );
10905
10906 }
10907
10908 }
10909
10910 }
10911
10912 _box$2.getCenter( center );
10913
10914 // second, try to find a boundingSphere with a radius smaller than the
10915 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
10916
10917 let maxRadiusSq = 0;
10918
10919 for ( let i = 0, il = position.count; i < il; i ++ ) {
10920
10921 _vector$8.fromBufferAttribute( position, i );
10922
10923 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10924
10925 }
10926
10927 // process morph attributes if present
10928
10930
10931 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {
10932
10935
10936 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {
10937
10938 _vector$8.fromBufferAttribute( morphAttribute, j );
10939
10940 if ( morphTargetsRelative ) {
10941
10942 _offset.fromBufferAttribute( position, j );
10943 _vector$8.add( _offset );
10944
10945 }
10946
10947 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );
10948
10949 }
10950
10951 }
10952
10953 }
10954
10955 this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
10956
10957 if ( isNaN( this.boundingSphere.radius ) ) {
10958
10959 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
10960
10961 }
10962
10963 }
10964
10965 }
10966
10967 computeTangents() {
10968
10969 const index = this.index;
10970 const attributes = this.attributes;
10971
10972 // based on http://www.terathon.com/code/tangent.html
10973 // (per vertex tangents)
10974
10975 if ( index === null ||
10976 attributes.position === undefined ||
10977 attributes.normal === undefined ||
10978 attributes.uv === undefined ) {
10979
10980 console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );
10981 return;
10982
10983 }
10984
10985 const indices = index.array;
10986 const positions = attributes.position.array;
10987 const normals = attributes.normal.array;
10988 const uvs = attributes.uv.array;
10989
10990 const nVertices = positions.length / 3;
10991
10992 if ( this.hasAttribute( 'tangent' ) === false ) {
10993
10994 this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
10995
10996 }
10997
10998 const tangents = this.getAttribute( 'tangent' ).array;
10999
11000 const tan1 = [], tan2 = [];
11001
11002 for ( let i = 0; i < nVertices; i ++ ) {
11003
11004 tan1[ i ] = new Vector3();
11005 tan2[ i ] = new Vector3();
11006
11007 }
11008
11009 const vA = new Vector3(),
11010 vB = new Vector3(),
11011 vC = new Vector3(),
11012
11013 uvA = new Vector2(),
11014 uvB = new Vector2(),
11015 uvC = new Vector2(),
11016
11017 sdir = new Vector3(),
11018 tdir = new Vector3();
11019
11020 function handleTriangle( a, b, c ) {
11021
11022 vA.fromArray( positions, a * 3 );
11023 vB.fromArray( positions, b * 3 );
11024 vC.fromArray( positions, c * 3 );
11025
11026 uvA.fromArray( uvs, a * 2 );
11027 uvB.fromArray( uvs, b * 2 );
11028 uvC.fromArray( uvs, c * 2 );
11029
11030 vB.sub( vA );
11031 vC.sub( vA );
11032
11033 uvB.sub( uvA );
11034 uvC.sub( uvA );
11035
11036 const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );
11037
11038 // silently ignore degenerate uv triangles having coincident or colinear vertices
11039
11040 if ( ! isFinite( r ) ) return;
11041
11042 sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );
11043 tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );
11044
11045 tan1[ a ].add( sdir );
11046 tan1[ b ].add( sdir );
11047 tan1[ c ].add( sdir );
11048
11049 tan2[ a ].add( tdir );
11050 tan2[ b ].add( tdir );
11051 tan2[ c ].add( tdir );
11052
11053 }
11054
11055 let groups = this.groups;
11056
11057 if ( groups.length === 0 ) {
11058
11059 groups = [ {
11060 start: 0,
11061 count: indices.length
11062 } ];
11063
11064 }
11065
11066 for ( let i = 0, il = groups.length; i < il; ++ i ) {
11067
11068 const group = groups[ i ];
11069
11070 const start = group.start;
11071 const count = group.count;
11072
11073 for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11074
11076 indices[ j + 0 ],
11077 indices[ j + 1 ],
11078 indices[ j + 2 ]
11079 );
11080
11081 }
11082
11083 }
11084
11085 const tmp = new Vector3(), tmp2 = new Vector3();
11086 const n = new Vector3(), n2 = new Vector3();
11087
11088 function handleVertex( v ) {
11089
11090 n.fromArray( normals, v * 3 );
11091 n2.copy( n );
11092
11093 const t = tan1[ v ];
11094
11095 // Gram-Schmidt orthogonalize
11096
11097 tmp.copy( t );
11098 tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
11099
11100 // Calculate handedness
11101
11102 tmp2.crossVectors( n2, t );
11103 const test = tmp2.dot( tan2[ v ] );
11104 const w = ( test < 0.0 ) ? - 1.0 : 1.0;
11105
11106 tangents[ v * 4 ] = tmp.x;
11107 tangents[ v * 4 + 1 ] = tmp.y;
11108 tangents[ v * 4 + 2 ] = tmp.z;
11109 tangents[ v * 4 + 3 ] = w;
11110
11111 }
11112
11113 for ( let i = 0, il = groups.length; i < il; ++ i ) {
11114
11115 const group = groups[ i ];
11116
11117 const start = group.start;
11118 const count = group.count;
11119
11120 for ( let j = start, jl = start + count; j < jl; j += 3 ) {
11121
11122 handleVertex( indices[ j + 0 ] );
11123 handleVertex( indices[ j + 1 ] );
11124 handleVertex( indices[ j + 2 ] );
11125
11126 }
11127
11128 }
11129
11130 }
11131
11133
11134 const index = this.index;
11135 const positionAttribute = this.getAttribute( 'position' );
11136
11137 if ( positionAttribute !== undefined ) {
11138
11139 let normalAttribute = this.getAttribute( 'normal' );
11140
11141 if ( normalAttribute === undefined ) {
11142
11144 this.setAttribute( 'normal', normalAttribute );
11145
11146 } else {
11147
11148 // reset existing normals to zero
11149
11150 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {
11151
11152 normalAttribute.setXYZ( i, 0, 0, 0 );
11153
11154 }
11155
11156 }
11157
11158 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
11159 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
11160 const cb = new Vector3(), ab = new Vector3();
11161
11162 // indexed elements
11163
11164 if ( index ) {
11165
11166 for ( let i = 0, il = index.count; i < il; i += 3 ) {
11167
11168 const vA = index.getX( i + 0 );
11169 const vB = index.getX( i + 1 );
11170 const vC = index.getX( i + 2 );
11171
11172 pA.fromBufferAttribute( positionAttribute, vA );
11173 pB.fromBufferAttribute( positionAttribute, vB );
11174 pC.fromBufferAttribute( positionAttribute, vC );
11175
11176 cb.subVectors( pC, pB );
11177 ab.subVectors( pA, pB );
11178 cb.cross( ab );
11179
11180 nA.fromBufferAttribute( normalAttribute, vA );
11181 nB.fromBufferAttribute( normalAttribute, vB );
11182 nC.fromBufferAttribute( normalAttribute, vC );
11183
11184 nA.add( cb );
11185 nB.add( cb );
11186 nC.add( cb );
11187
11188 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );
11189 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );
11190 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );
11191
11192 }
11193
11194 } else {
11195
11196 // non-indexed elements (unconnected triangle soup)
11197
11198 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {
11199
11200 pA.fromBufferAttribute( positionAttribute, i + 0 );
11201 pB.fromBufferAttribute( positionAttribute, i + 1 );
11202 pC.fromBufferAttribute( positionAttribute, i + 2 );
11203
11204 cb.subVectors( pC, pB );
11205 ab.subVectors( pA, pB );
11206 cb.cross( ab );
11207
11208 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );
11209 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );
11210 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );
11211
11212 }
11213
11214 }
11215
11216 this.normalizeNormals();
11217
11218 normalAttribute.needsUpdate = true;
11219
11220 }
11221
11222 }
11223
11225
11226 const normals = this.attributes.normal;
11227
11228 for ( let i = 0, il = normals.count; i < il; i ++ ) {
11229
11230 _vector$8.fromBufferAttribute( normals, i );
11231
11232 _vector$8.normalize();
11233
11234 normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );
11235
11236 }
11237
11238 }
11239
11240 toNonIndexed() {
11241
11243
11244 const array = attribute.array;
11245 const itemSize = attribute.itemSize;
11246 const normalized = attribute.normalized;
11247
11248 const array2 = new array.constructor( indices.length * itemSize );
11249
11250 let index = 0, index2 = 0;
11251
11252 for ( let i = 0, l = indices.length; i < l; i ++ ) {
11253
11254 if ( attribute.isInterleavedBufferAttribute ) {
11255
11256 index = indices[ i ] * attribute.data.stride + attribute.offset;
11257
11258 } else {
11259
11260 index = indices[ i ] * itemSize;
11261
11262 }
11263
11264 for ( let j = 0; j < itemSize; j ++ ) {
11265
11266 array2[ index2 ++ ] = array[ index ++ ];
11267
11268 }
11269
11270 }
11271
11272 return new BufferAttribute( array2, itemSize, normalized );
11273
11274 }
11275
11276 //
11277
11278 if ( this.index === null ) {
11279
11280 console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );
11281 return this;
11282
11283 }
11284
11285 const geometry2 = new BufferGeometry();
11286
11287 const indices = this.index.array;
11288 const attributes = this.attributes;
11289
11290 // attributes
11291
11292 for ( const name in attributes ) {
11293
11294 const attribute = attributes[ name ];
11295
11297
11298 geometry2.setAttribute( name, newAttribute );
11299
11300 }
11301
11302 // morph attributes
11303
11304 const morphAttributes = this.morphAttributes;
11305
11306 for ( const name in morphAttributes ) {
11307
11308 const morphArray = [];
11309 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11310
11311 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
11312
11313 const attribute = morphAttribute[ i ];
11314
11316
11317 morphArray.push( newAttribute );
11318
11319 }
11320
11321 geometry2.morphAttributes[ name ] = morphArray;
11322
11323 }
11324
11325 geometry2.morphTargetsRelative = this.morphTargetsRelative;
11326
11327 // groups
11328
11329 const groups = this.groups;
11330
11331 for ( let i = 0, l = groups.length; i < l; i ++ ) {
11332
11333 const group = groups[ i ];
11334 geometry2.addGroup( group.start, group.count, group.materialIndex );
11335
11336 }
11337
11338 return geometry2;
11339
11340 }
11341
11342 toJSON() {
11343
11344 const data = {
11345 metadata: {
11346 version: 4.6,
11347 type: 'BufferGeometry',
11348 generator: 'BufferGeometry.toJSON'
11349 }
11350 };
11351
11352 // standard BufferGeometry serialization
11353
11354 data.uuid = this.uuid;
11355 data.type = this.type;
11356 if ( this.name !== '' ) data.name = this.name;
11357 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
11358
11359 if ( this.parameters !== undefined ) {
11360
11361 const parameters = this.parameters;
11362
11363 for ( const key in parameters ) {
11364
11365 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
11366
11367 }
11368
11369 return data;
11370
11371 }
11372
11373 // for simplicity the code assumes attributes are not shared across geometries, see #15811
11374
11375 data.data = { attributes: {} };
11376
11377 const index = this.index;
11378
11379 if ( index !== null ) {
11380
11381 data.data.index = {
11382 type: index.array.constructor.name,
11383 array: Array.prototype.slice.call( index.array )
11384 };
11385
11386 }
11387
11388 const attributes = this.attributes;
11389
11390 for ( const key in attributes ) {
11391
11392 const attribute = attributes[ key ];
11393
11394 data.data.attributes[ key ] = attribute.toJSON( data.data );
11395
11396 }
11397
11398 const morphAttributes = {};
11399 let hasMorphAttributes = false;
11400
11401 for ( const key in this.morphAttributes ) {
11402
11403 const attributeArray = this.morphAttributes[ key ];
11404
11405 const array = [];
11406
11407 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
11408
11409 const attribute = attributeArray[ i ];
11410
11411 array.push( attribute.toJSON( data.data ) );
11412
11413 }
11414
11415 if ( array.length > 0 ) {
11416
11418
11419 hasMorphAttributes = true;
11420
11421 }
11422
11423 }
11424
11425 if ( hasMorphAttributes ) {
11426
11427 data.data.morphAttributes = morphAttributes;
11428 data.data.morphTargetsRelative = this.morphTargetsRelative;
11429
11430 }
11431
11432 const groups = this.groups;
11433
11434 if ( groups.length > 0 ) {
11435
11436 data.data.groups = JSON.parse( JSON.stringify( groups ) );
11437
11438 }
11439
11440 const boundingSphere = this.boundingSphere;
11441
11442 if ( boundingSphere !== null ) {
11443
11444 data.data.boundingSphere = {
11445 center: boundingSphere.center.toArray(),
11446 radius: boundingSphere.radius
11447 };
11448
11449 }
11450
11451 return data;
11452
11453 }
11454
11455 clone() {
11456
11457 return new this.constructor().copy( this );
11458
11459 }
11460
11461 copy( source ) {
11462
11463 // reset
11464
11465 this.index = null;
11466 this.attributes = {};
11467 this.morphAttributes = {};
11468 this.groups = [];
11469 this.boundingBox = null;
11470 this.boundingSphere = null;
11471
11472 // used for storing cloned, shared data
11473
11474 const data = {};
11475
11476 // name
11477
11478 this.name = source.name;
11479
11480 // index
11481
11482 const index = source.index;
11483
11484 if ( index !== null ) {
11485
11486 this.setIndex( index.clone( data ) );
11487
11488 }
11489
11490 // attributes
11491
11492 const attributes = source.attributes;
11493
11494 for ( const name in attributes ) {
11495
11496 const attribute = attributes[ name ];
11497 this.setAttribute( name, attribute.clone( data ) );
11498
11499 }
11500
11501 // morph attributes
11502
11503 const morphAttributes = source.morphAttributes;
11504
11505 for ( const name in morphAttributes ) {
11506
11507 const array = [];
11508 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
11509
11510 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {
11511
11512 array.push( morphAttribute[ i ].clone( data ) );
11513
11514 }
11515
11516 this.morphAttributes[ name ] = array;
11517
11518 }
11519
11520 this.morphTargetsRelative = source.morphTargetsRelative;
11521
11522 // groups
11523
11524 const groups = source.groups;
11525
11526 for ( let i = 0, l = groups.length; i < l; i ++ ) {
11527
11528 const group = groups[ i ];
11529 this.addGroup( group.start, group.count, group.materialIndex );
11530
11531 }
11532
11533 // bounding box
11534
11535 const boundingBox = source.boundingBox;
11536
11537 if ( boundingBox !== null ) {
11538
11539 this.boundingBox = boundingBox.clone();
11540
11541 }
11542
11543 // bounding sphere
11544
11545 const boundingSphere = source.boundingSphere;
11546
11547 if ( boundingSphere !== null ) {
11548
11549 this.boundingSphere = boundingSphere.clone();
11550
11551 }
11552
11553 // draw range
11554
11555 this.drawRange.start = source.drawRange.start;
11556 this.drawRange.count = source.drawRange.count;
11557
11558 // user data
11559
11560 this.userData = source.userData;
11561
11562 return this;
11563
11564 }
11565
11566 dispose() {
11567
11568 this.dispatchEvent( { type: 'dispose' } );
11569
11570 }
11571
11572 }
11573
11574 const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();
11575 const _ray$3 = /*@__PURE__*/ new Ray();
11576 const _sphere$6 = /*@__PURE__*/ new Sphere();
11577 const _sphereHitAt = /*@__PURE__*/ new Vector3();
11578
11579 const _vA$1 = /*@__PURE__*/ new Vector3();
11580 const _vB$1 = /*@__PURE__*/ new Vector3();
11581 const _vC$1 = /*@__PURE__*/ new Vector3();
11582
11583 const _tempA = /*@__PURE__*/ new Vector3();
11584 const _morphA = /*@__PURE__*/ new Vector3();
11585
11586 const _uvA$1 = /*@__PURE__*/ new Vector2();
11587 const _uvB$1 = /*@__PURE__*/ new Vector2();
11588 const _uvC$1 = /*@__PURE__*/ new Vector2();
11589
11590 const _normalA = /*@__PURE__*/ new Vector3();
11591 const _normalB = /*@__PURE__*/ new Vector3();
11592 const _normalC = /*@__PURE__*/ new Vector3();
11593
11594 const _intersectionPoint = /*@__PURE__*/ new Vector3();
11595 const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
11596
11597 class Mesh extends Object3D {
11598
11600
11601 super();
11602
11603 this.isMesh = true;
11604
11605 this.type = 'Mesh';
11606
11607 this.geometry = geometry;
11608 this.material = material;
11609
11610 this.updateMorphTargets();
11611
11612 }
11613
11614 copy( source, recursive ) {
11615
11616 super.copy( source, recursive );
11617
11618 if ( source.morphTargetInfluences !== undefined ) {
11619
11620 this.morphTargetInfluences = source.morphTargetInfluences.slice();
11621
11622 }
11623
11624 if ( source.morphTargetDictionary !== undefined ) {
11625
11626 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
11627
11628 }
11629
11630 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
11631 this.geometry = source.geometry;
11632
11633 return this;
11634
11635 }
11636
11638
11639 const geometry = this.geometry;
11640
11641 const morphAttributes = geometry.morphAttributes;
11642 const keys = Object.keys( morphAttributes );
11643
11644 if ( keys.length > 0 ) {
11645
11646 const morphAttribute = morphAttributes[ keys[ 0 ] ];
11647
11648 if ( morphAttribute !== undefined ) {
11649
11650 this.morphTargetInfluences = [];
11651 this.morphTargetDictionary = {};
11652
11653 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
11654
11655 const name = morphAttribute[ m ].name || String( m );
11656
11657 this.morphTargetInfluences.push( 0 );
11658 this.morphTargetDictionary[ name ] = m;
11659
11660 }
11661
11662 }
11663
11664 }
11665
11666 }
11667
11668 getVertexPosition( index, target ) {
11669
11670 const geometry = this.geometry;
11671 const position = geometry.attributes.position;
11672 const morphPosition = geometry.morphAttributes.position;
11673 const morphTargetsRelative = geometry.morphTargetsRelative;
11674
11675 target.fromBufferAttribute( position, index );
11676
11678
11679 if ( morphPosition && morphInfluences ) {
11680
11681 _morphA.set( 0, 0, 0 );
11682
11683 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) {
11684
11685 const influence = morphInfluences[ i ];
11686 const morphAttribute = morphPosition[ i ];
11687
11688 if ( influence === 0 ) continue;
11689
11690 _tempA.fromBufferAttribute( morphAttribute, index );
11691
11692 if ( morphTargetsRelative ) {
11693
11694 _morphA.addScaledVector( _tempA, influence );
11695
11696 } else {
11697
11698 _morphA.addScaledVector( _tempA.sub( target ), influence );
11699
11700 }
11701
11702 }
11703
11704 target.add( _morphA );
11705
11706 }
11707
11708 return target;
11709
11710 }
11711
11713
11714 const geometry = this.geometry;
11715 const material = this.material;
11716 const matrixWorld = this.matrixWorld;
11717
11718 if ( material === undefined ) return;
11719
11720 // test with bounding sphere in world space
11721
11722 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
11723
11724 _sphere$6.copy( geometry.boundingSphere );
11725 _sphere$6.applyMatrix4( matrixWorld );
11726
11727 // check distance from ray origin to bounding sphere
11728
11729 _ray$3.copy( raycaster.ray ).recast( raycaster.near );
11730
11731 if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {
11732
11733 if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;
11734
11735 if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;
11736
11737 }
11738
11739 // convert ray to local space of mesh
11740
11741 _inverseMatrix$3.copy( matrixWorld ).invert();
11742 _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );
11743
11744 // test with bounding box in local space
11745
11746 if ( geometry.boundingBox !== null ) {
11747
11748 if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;
11749
11750 }
11751
11752 // test for intersections with geometry
11753
11755
11756 }
11757
11759
11761
11762 const geometry = this.geometry;
11763 const material = this.material;
11764
11765 const index = geometry.index;
11766 const position = geometry.attributes.position;
11767 const uv = geometry.attributes.uv;
11768 const uv1 = geometry.attributes.uv1;
11769 const normal = geometry.attributes.normal;
11770 const groups = geometry.groups;
11771 const drawRange = geometry.drawRange;
11772
11773 if ( index !== null ) {
11774
11775 // indexed buffer geometry
11776
11777 if ( Array.isArray( material ) ) {
11778
11779 for ( let i = 0, il = groups.length; i < il; i ++ ) {
11780
11781 const group = groups[ i ];
11782 const groupMaterial = material[ group.materialIndex ];
11783
11784 const start = Math.max( group.start, drawRange.start );
11785 const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11786
11787 for ( let j = start, jl = end; j < jl; j += 3 ) {
11788
11789 const a = index.getX( j );
11790 const b = index.getX( j + 1 );
11791 const c = index.getX( j + 2 );
11792
11794
11795 if ( intersection ) {
11796
11797 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics
11798 intersection.face.materialIndex = group.materialIndex;
11799 intersects.push( intersection );
11800
11801 }
11802
11803 }
11804
11805 }
11806
11807 } else {
11808
11809 const start = Math.max( 0, drawRange.start );
11810 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
11811
11812 for ( let i = start, il = end; i < il; i += 3 ) {
11813
11814 const a = index.getX( i );
11815 const b = index.getX( i + 1 );
11816 const c = index.getX( i + 2 );
11817
11819
11820 if ( intersection ) {
11821
11822 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics
11823 intersects.push( intersection );
11824
11825 }
11826
11827 }
11828
11829 }
11830
11831 } else if ( position !== undefined ) {
11832
11833 // non-indexed buffer geometry
11834
11835 if ( Array.isArray( material ) ) {
11836
11837 for ( let i = 0, il = groups.length; i < il; i ++ ) {
11838
11839 const group = groups[ i ];
11840 const groupMaterial = material[ group.materialIndex ];
11841
11842 const start = Math.max( group.start, drawRange.start );
11843 const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );
11844
11845 for ( let j = start, jl = end; j < jl; j += 3 ) {
11846
11847 const a = j;
11848 const b = j + 1;
11849 const c = j + 2;
11850
11852
11853 if ( intersection ) {
11854
11855 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics
11856 intersection.face.materialIndex = group.materialIndex;
11857 intersects.push( intersection );
11858
11859 }
11860
11861 }
11862
11863 }
11864
11865 } else {
11866
11867 const start = Math.max( 0, drawRange.start );
11868 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) );
11869
11870 for ( let i = start, il = end; i < il; i += 3 ) {
11871
11872 const a = i;
11873 const b = i + 1;
11874 const c = i + 2;
11875
11877
11878 if ( intersection ) {
11879
11880 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics
11881 intersects.push( intersection );
11882
11883 }
11884
11885 }
11886
11887 }
11888
11889 }
11890
11891 }
11892
11893 }
11894
11895 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
11896
11897 let intersect;
11898
11899 if ( material.side === BackSide ) {
11900
11901 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
11902
11903 } else {
11904
11905 intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );
11906
11907 }
11908
11909 if ( intersect === null ) return null;
11910
11912 _intersectionPointWorld.applyMatrix4( object.matrixWorld );
11913
11914 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );
11915
11917
11918 return {
11921 object: object
11922 };
11923
11924 }
11925
11926 function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {
11927
11928 object.getVertexPosition( a, _vA$1 );
11929 object.getVertexPosition( b, _vB$1 );
11930 object.getVertexPosition( c, _vC$1 );
11931
11933
11934 if ( intersection ) {
11935
11936 if ( uv ) {
11937
11938 _uvA$1.fromBufferAttribute( uv, a );
11939 _uvB$1.fromBufferAttribute( uv, b );
11940 _uvC$1.fromBufferAttribute( uv, c );
11941
11942 intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11943
11944 }
11945
11946 if ( uv1 ) {
11947
11948 _uvA$1.fromBufferAttribute( uv1, a );
11949 _uvB$1.fromBufferAttribute( uv1, b );
11950 _uvC$1.fromBufferAttribute( uv1, c );
11951
11952 intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
11953 intersection.uv2 = intersection.uv1; // @deprecated, r152
11954
11955 }
11956
11957 if ( normal ) {
11958
11959 _normalA.fromBufferAttribute( normal, a );
11960 _normalB.fromBufferAttribute( normal, b );
11961 _normalC.fromBufferAttribute( normal, c );
11962
11963 intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );
11964
11965 if ( intersection.normal.dot( ray.direction ) > 0 ) {
11966
11967 intersection.normal.multiplyScalar( - 1 );
11968
11969 }
11970
11971 }
11972
11973 const face = {
11974 a: a,
11975 b: b,
11976 c: c,
11977 normal: new Vector3(),
11978 materialIndex: 0
11979 };
11980
11981 Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
11982
11983 intersection.face = face;
11984
11985 }
11986
11987 return intersection;
11988
11989 }
11990
11991 class BoxGeometry extends BufferGeometry {
11992
11993 constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
11994
11995 super();
11996
11997 this.type = 'BoxGeometry';
11998
11999 this.parameters = {
12000 width: width,
12001 height: height,
12002 depth: depth,
12006 };
12007
12008 const scope = this;
12009
12010 // segments
12011
12012 widthSegments = Math.floor( widthSegments );
12014 depthSegments = Math.floor( depthSegments );
12015
12016 // buffers
12017
12018 const indices = [];
12019 const vertices = [];
12020 const normals = [];
12021 const uvs = [];
12022
12023 // helper variables
12024
12026 let groupStart = 0;
12027
12028 // build each side of the box geometry
12029
12030 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
12031 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
12032 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
12033 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
12034 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
12035 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
12036
12037 // build geometry
12038
12039 this.setIndex( indices );
12040 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
12041 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
12042 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
12043
12044 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
12045
12046 const segmentWidth = width / gridX;
12047 const segmentHeight = height / gridY;
12048
12049 const widthHalf = width / 2;
12050 const heightHalf = height / 2;
12051 const depthHalf = depth / 2;
12052
12053 const gridX1 = gridX + 1;
12054 const gridY1 = gridY + 1;
12055
12056 let vertexCounter = 0;
12057 let groupCount = 0;
12058
12059 const vector = new Vector3();
12060
12061 // generate vertices, normals and uvs
12062
12063 for ( let iy = 0; iy < gridY1; iy ++ ) {
12064
12065 const y = iy * segmentHeight - heightHalf;
12066
12067 for ( let ix = 0; ix < gridX1; ix ++ ) {
12068
12069 const x = ix * segmentWidth - widthHalf;
12070
12071 // set values to correct vector component
12072
12073 vector[ u ] = x * udir;
12074 vector[ v ] = y * vdir;
12075 vector[ w ] = depthHalf;
12076
12077 // now apply vector to vertex buffer
12078
12079 vertices.push( vector.x, vector.y, vector.z );
12080
12081 // set values to correct vector component
12082
12083 vector[ u ] = 0;
12084 vector[ v ] = 0;
12085 vector[ w ] = depth > 0 ? 1 : - 1;
12086
12087 // now apply vector to normal buffer
12088
12089 normals.push( vector.x, vector.y, vector.z );
12090
12091 // uvs
12092
12093 uvs.push( ix / gridX );
12094 uvs.push( 1 - ( iy / gridY ) );
12095
12096 // counters
12097
12098 vertexCounter += 1;
12099
12100 }
12101
12102 }
12103
12104 // indices
12105
12106 // 1. you need three indices to draw a single face
12107 // 2. a single segment consists of two faces
12108 // 3. so we need to generate six (2*3) indices per segment
12109
12110 for ( let iy = 0; iy < gridY; iy ++ ) {
12111
12112 for ( let ix = 0; ix < gridX; ix ++ ) {
12113
12114 const a = numberOfVertices + ix + gridX1 * iy;
12115 const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
12116 const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
12117 const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
12118
12119 // faces
12120
12121 indices.push( a, b, d );
12122 indices.push( b, c, d );
12123
12124 // increase counter
12125
12126 groupCount += 6;
12127
12128 }
12129
12130 }
12131
12132 // add a group to the geometry. this will ensure multi material support
12133
12135
12136 // calculate new start value for groups
12137
12139
12140 // update total number of vertices
12141
12143
12144 }
12145
12146 }
12147
12148 copy( source ) {
12149
12150 super.copy( source );
12151
12152 this.parameters = Object.assign( {}, source.parameters );
12153
12154 return this;
12155
12156 }
12157
12158 static fromJSON( data ) {
12159
12160 return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );
12161
12162 }
12163
12164 }
12165
12170 function cloneUniforms( src ) {
12171
12172 const dst = {};
12173
12174 for ( const u in src ) {
12175
12176 dst[ u ] = {};
12177
12178 for ( const p in src[ u ] ) {
12179
12180 const property = src[ u ][ p ];
12181
12182 if ( property && ( property.isColor ||
12183 property.isMatrix3 || property.isMatrix4 ||
12184 property.isVector2 || property.isVector3 || property.isVector4 ||
12185 property.isTexture || property.isQuaternion ) ) {
12186
12187 if ( property.isRenderTargetTexture ) {
12188
12189 console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );
12190 dst[ u ][ p ] = null;
12191
12192 } else {
12193
12194 dst[ u ][ p ] = property.clone();
12195
12196 }
12197
12198 } else if ( Array.isArray( property ) ) {
12199
12200 dst[ u ][ p ] = property.slice();
12201
12202 } else {
12203
12204 dst[ u ][ p ] = property;
12205
12206 }
12207
12208 }
12209
12210 }
12211
12212 return dst;
12213
12214 }
12215
12216 function mergeUniforms( uniforms ) {
12217
12218 const merged = {};
12219
12220 for ( let u = 0; u < uniforms.length; u ++ ) {
12221
12222 const tmp = cloneUniforms( uniforms[ u ] );
12223
12224 for ( const p in tmp ) {
12225
12226 merged[ p ] = tmp[ p ];
12227
12228 }
12229
12230 }
12231
12232 return merged;
12233
12234 }
12235
12236 function cloneUniformsGroups( src ) {
12237
12238 const dst = [];
12239
12240 for ( let u = 0; u < src.length; u ++ ) {
12241
12242 dst.push( src[ u ].clone() );
12243
12244 }
12245
12246 return dst;
12247
12248 }
12249
12250 function getUnlitUniformColorSpace( renderer ) {
12251
12252 if ( renderer.getRenderTarget() === null ) {
12253
12254 // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398
12255 return renderer.outputColorSpace;
12256
12257 }
12258
12259 return ColorManagement.workingColorSpace;
12260
12261 }
12262
12263 // Legacy
12264
12266
12267 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
12268
12269 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
12270
12271 class ShaderMaterial extends Material {
12272
12274
12275 super();
12276
12277 this.isShaderMaterial = true;
12278
12279 this.type = 'ShaderMaterial';
12280
12281 this.defines = {};
12282 this.uniforms = {};
12283 this.uniformsGroups = [];
12284
12287
12288 this.linewidth = 1;
12289
12290 this.wireframe = false;
12291 this.wireframeLinewidth = 1;
12292
12293 this.fog = false; // set to use scene fog
12294 this.lights = false; // set to use scene lights
12295 this.clipping = false; // set to use user-defined clipping planes
12296
12297 this.forceSinglePass = true;
12298
12299 this.extensions = {
12300 derivatives: false, // set to use derivatives
12301 fragDepth: false, // set to use fragment depth values
12302 drawBuffers: false, // set to use draw buffers
12303 shaderTextureLOD: false, // set to use shader texture LOD
12304 clipCullDistance: false // set to use vertex shader clipping
12305 };
12306
12307 // When rendered geometry doesn't include these attributes but the material does,
12308 // use these default values in WebGL. This avoids errors when buffer data is missing.
12309 this.defaultAttributeValues = {
12310 'color': [ 1, 1, 1 ],
12311 'uv': [ 0, 0 ],
12312 'uv1': [ 0, 0 ]
12313 };
12314
12316 this.uniformsNeedUpdate = false;
12317
12318 this.glslVersion = null;
12319
12320 if ( parameters !== undefined ) {
12321
12322 this.setValues( parameters );
12323
12324 }
12325
12326 }
12327
12328 copy( source ) {
12329
12330 super.copy( source );
12331
12332 this.fragmentShader = source.fragmentShader;
12333 this.vertexShader = source.vertexShader;
12334
12335 this.uniforms = cloneUniforms( source.uniforms );
12336 this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );
12337
12338 this.defines = Object.assign( {}, source.defines );
12339
12340 this.wireframe = source.wireframe;
12341 this.wireframeLinewidth = source.wireframeLinewidth;
12342
12343 this.fog = source.fog;
12344 this.lights = source.lights;
12345 this.clipping = source.clipping;
12346
12347 this.extensions = Object.assign( {}, source.extensions );
12348
12349 this.glslVersion = source.glslVersion;
12350
12351 return this;
12352
12353 }
12354
12355 toJSON( meta ) {
12356
12357 const data = super.toJSON( meta );
12358
12359 data.glslVersion = this.glslVersion;
12360 data.uniforms = {};
12361
12362 for ( const name in this.uniforms ) {
12363
12364 const uniform = this.uniforms[ name ];
12365 const value = uniform.value;
12366
12367 if ( value && value.isTexture ) {
12368
12369 data.uniforms[ name ] = {
12370 type: 't',
12371 value: value.toJSON( meta ).uuid
12372 };
12373
12374 } else if ( value && value.isColor ) {
12375
12376 data.uniforms[ name ] = {
12377 type: 'c',
12378 value: value.getHex()
12379 };
12380
12381 } else if ( value && value.isVector2 ) {
12382
12383 data.uniforms[ name ] = {
12384 type: 'v2',
12385 value: value.toArray()
12386 };
12387
12388 } else if ( value && value.isVector3 ) {
12389
12390 data.uniforms[ name ] = {
12391 type: 'v3',
12392 value: value.toArray()
12393 };
12394
12395 } else if ( value && value.isVector4 ) {
12396
12397 data.uniforms[ name ] = {
12398 type: 'v4',
12399 value: value.toArray()
12400 };
12401
12402 } else if ( value && value.isMatrix3 ) {
12403
12404 data.uniforms[ name ] = {
12405 type: 'm3',
12406 value: value.toArray()
12407 };
12408
12409 } else if ( value && value.isMatrix4 ) {
12410
12411 data.uniforms[ name ] = {
12412 type: 'm4',
12413 value: value.toArray()
12414 };
12415
12416 } else {
12417
12418 data.uniforms[ name ] = {
12419 value: value
12420 };
12421
12422 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
12423
12424 }
12425
12426 }
12427
12428 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
12429
12430 data.vertexShader = this.vertexShader;
12431 data.fragmentShader = this.fragmentShader;
12432
12433 data.lights = this.lights;
12434 data.clipping = this.clipping;
12435
12436 const extensions = {};
12437
12438 for ( const key in this.extensions ) {
12439
12440 if ( this.extensions[ key ] === true ) extensions[ key ] = true;
12441
12442 }
12443
12444 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
12445
12446 return data;
12447
12448 }
12449
12450 }
12451
12452 class Camera extends Object3D {
12453
12454 constructor() {
12455
12456 super();
12457
12458 this.isCamera = true;
12459
12460 this.type = 'Camera';
12461
12462 this.matrixWorldInverse = new Matrix4();
12463
12464 this.projectionMatrix = new Matrix4();
12465 this.projectionMatrixInverse = new Matrix4();
12466
12468
12469 }
12470
12471 copy( source, recursive ) {
12472
12473 super.copy( source, recursive );
12474
12475 this.matrixWorldInverse.copy( source.matrixWorldInverse );
12476
12477 this.projectionMatrix.copy( source.projectionMatrix );
12478 this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
12479
12480 this.coordinateSystem = source.coordinateSystem;
12481
12482 return this;
12483
12484 }
12485
12486 getWorldDirection( target ) {
12487
12488 return super.getWorldDirection( target ).negate();
12489
12490 }
12491
12493
12494 super.updateMatrixWorld( force );
12495
12496 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12497
12498 }
12499
12501
12502 super.updateWorldMatrix( updateParents, updateChildren );
12503
12504 this.matrixWorldInverse.copy( this.matrixWorld ).invert();
12505
12506 }
12507
12508 clone() {
12509
12510 return new this.constructor().copy( this );
12511
12512 }
12513
12514 }
12515
12516 class PerspectiveCamera extends Camera {
12517
12518 constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {
12519
12520 super();
12521
12522 this.isPerspectiveCamera = true;
12523
12524 this.type = 'PerspectiveCamera';
12525
12526 this.fov = fov;
12527 this.zoom = 1;
12528
12529 this.near = near;
12530 this.far = far;
12531 this.focus = 10;
12532
12533 this.aspect = aspect;
12534 this.view = null;
12535
12536 this.filmGauge = 35; // width of the film (default in millimeters)
12537 this.filmOffset = 0; // horizontal film offset (same unit as gauge)
12538
12540
12541 }
12542
12543 copy( source, recursive ) {
12544
12545 super.copy( source, recursive );
12546
12547 this.fov = source.fov;
12548 this.zoom = source.zoom;
12549
12550 this.near = source.near;
12551 this.far = source.far;
12552 this.focus = source.focus;
12553
12554 this.aspect = source.aspect;
12555 this.view = source.view === null ? null : Object.assign( {}, source.view );
12556
12557 this.filmGauge = source.filmGauge;
12558 this.filmOffset = source.filmOffset;
12559
12560 return this;
12561
12562 }
12563
12573
12575 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
12576
12577 this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );
12579
12580 }
12581
12585 getFocalLength() {
12586
12587 const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );
12588
12589 return 0.5 * this.getFilmHeight() / vExtentSlope;
12590
12591 }
12592
12593 getEffectiveFOV() {
12594
12595 return RAD2DEG * 2 * Math.atan(
12596 Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );
12597
12598 }
12599
12600 getFilmWidth() {
12601
12602 // film not completely covered in portrait format (aspect < 1)
12603 return this.filmGauge * Math.min( this.aspect, 1 );
12604
12605 }
12606
12607 getFilmHeight() {
12608
12609 // film not completely covered in landscape format (aspect > 1)
12610 return this.filmGauge / Math.max( this.aspect, 1 );
12611
12612 }
12613
12650
12651 this.aspect = fullWidth / fullHeight;
12652
12653 if ( this.view === null ) {
12654
12655 this.view = {
12656 enabled: true,
12657 fullWidth: 1,
12658 fullHeight: 1,
12659 offsetX: 0,
12660 offsetY: 0,
12661 width: 1,
12662 height: 1
12663 };
12664
12665 }
12666
12667 this.view.enabled = true;
12668 this.view.fullWidth = fullWidth;
12669 this.view.fullHeight = fullHeight;
12670 this.view.offsetX = x;
12671 this.view.offsetY = y;
12672 this.view.width = width;
12673 this.view.height = height;
12674
12676
12677 }
12678
12679 clearViewOffset() {
12680
12681 if ( this.view !== null ) {
12682
12683 this.view.enabled = false;
12684
12685 }
12686
12688
12689 }
12690
12692
12693 const near = this.near;
12694 let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;
12695 let height = 2 * top;
12696 let width = this.aspect * height;
12697 let left = - 0.5 * width;
12698 const view = this.view;
12699
12700 if ( this.view !== null && this.view.enabled ) {
12701
12702 const fullWidth = view.fullWidth,
12703 fullHeight = view.fullHeight;
12704
12705 left += view.offsetX * width / fullWidth;
12706 top -= view.offsetY * height / fullHeight;
12707 width *= view.width / fullWidth;
12708 height *= view.height / fullHeight;
12709
12710 }
12711
12712 const skew = this.filmOffset;
12713 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
12714
12715 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );
12716
12717 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
12718
12719 }
12720
12721 toJSON( meta ) {
12722
12723 const data = super.toJSON( meta );
12724
12725 data.object.fov = this.fov;
12726 data.object.zoom = this.zoom;
12727
12728 data.object.near = this.near;
12729 data.object.far = this.far;
12730 data.object.focus = this.focus;
12731
12732 data.object.aspect = this.aspect;
12733
12734 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12735
12736 data.object.filmGauge = this.filmGauge;
12737 data.object.filmOffset = this.filmOffset;
12738
12739 return data;
12740
12741 }
12742
12743 }
12744
12745 const fov = - 90; // negative fov is not an error
12746 const aspect = 1;
12747
12748 class CubeCamera extends Object3D {
12749
12751
12752 super();
12753
12754 this.type = 'CubeCamera';
12755
12757 this.coordinateSystem = null;
12758 this.activeMipmapLevel = 0;
12759
12760 const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
12761 cameraPX.layers = this.layers;
12762 this.add( cameraPX );
12763
12764 const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
12765 cameraNX.layers = this.layers;
12766 this.add( cameraNX );
12767
12768 const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
12769 cameraPY.layers = this.layers;
12770 this.add( cameraPY );
12771
12772 const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
12773 cameraNY.layers = this.layers;
12774 this.add( cameraNY );
12775
12776 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
12777 cameraPZ.layers = this.layers;
12778 this.add( cameraPZ );
12779
12780 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
12781 cameraNZ.layers = this.layers;
12782 this.add( cameraNZ );
12783
12784 }
12785
12787
12789
12790 const cameras = this.children.concat();
12791
12793
12794 for ( const camera of cameras ) this.remove( camera );
12795
12797
12798 cameraPX.up.set( 0, 1, 0 );
12799 cameraPX.lookAt( 1, 0, 0 );
12800
12801 cameraNX.up.set( 0, 1, 0 );
12802 cameraNX.lookAt( - 1, 0, 0 );
12803
12804 cameraPY.up.set( 0, 0, - 1 );
12805 cameraPY.lookAt( 0, 1, 0 );
12806
12807 cameraNY.up.set( 0, 0, 1 );
12808 cameraNY.lookAt( 0, - 1, 0 );
12809
12810 cameraPZ.up.set( 0, 1, 0 );
12811 cameraPZ.lookAt( 0, 0, 1 );
12812
12813 cameraNZ.up.set( 0, 1, 0 );
12814 cameraNZ.lookAt( 0, 0, - 1 );
12815
12816 } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
12817
12818 cameraPX.up.set( 0, - 1, 0 );
12819 cameraPX.lookAt( - 1, 0, 0 );
12820
12821 cameraNX.up.set( 0, - 1, 0 );
12822 cameraNX.lookAt( 1, 0, 0 );
12823
12824 cameraPY.up.set( 0, 0, 1 );
12825 cameraPY.lookAt( 0, 1, 0 );
12826
12827 cameraNY.up.set( 0, 0, - 1 );
12828 cameraNY.lookAt( 0, - 1, 0 );
12829
12830 cameraPZ.up.set( 0, - 1, 0 );
12831 cameraPZ.lookAt( 0, 0, 1 );
12832
12833 cameraNZ.up.set( 0, - 1, 0 );
12834 cameraNZ.lookAt( 0, 0, - 1 );
12835
12836 } else {
12837
12838 throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );
12839
12840 }
12841
12842 for ( const camera of cameras ) {
12843
12844 this.add( camera );
12845
12846 camera.updateMatrixWorld();
12847
12848 }
12849
12850 }
12851
12852 update( renderer, scene ) {
12853
12854 if ( this.parent === null ) this.updateMatrixWorld();
12855
12856 const { renderTarget, activeMipmapLevel } = this;
12857
12858 if ( this.coordinateSystem !== renderer.coordinateSystem ) {
12859
12860 this.coordinateSystem = renderer.coordinateSystem;
12861
12863
12864 }
12865
12867
12868 const currentRenderTarget = renderer.getRenderTarget();
12869 const currentActiveCubeFace = renderer.getActiveCubeFace();
12870 const currentActiveMipmapLevel = renderer.getActiveMipmapLevel();
12871
12872 const currentXrEnabled = renderer.xr.enabled;
12873
12874 renderer.xr.enabled = false;
12875
12876 const generateMipmaps = renderTarget.texture.generateMipmaps;
12877
12878 renderTarget.texture.generateMipmaps = false;
12879
12880 renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel );
12881 renderer.render( scene, cameraPX );
12882
12883 renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel );
12884 renderer.render( scene, cameraNX );
12885
12886 renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel );
12887 renderer.render( scene, cameraPY );
12888
12889 renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel );
12890 renderer.render( scene, cameraNY );
12891
12892 renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel );
12893 renderer.render( scene, cameraPZ );
12894
12895 // mipmaps are generated during the last call of render()
12896 // at this point, all sides of the cube render target are defined
12897
12898 renderTarget.texture.generateMipmaps = generateMipmaps;
12899
12900 renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );
12901 renderer.render( scene, cameraNZ );
12902
12904
12905 renderer.xr.enabled = currentXrEnabled;
12906
12907 renderTarget.texture.needsPMREMUpdate = true;
12908
12909 }
12910
12911 }
12912
12913 class CubeTexture extends Texture {
12914
12916
12917 images = images !== undefined ? images : [];
12919
12921
12922 this.isCubeTexture = true;
12923
12924 this.flipY = false;
12925
12926 }
12927
12928 get images() {
12929
12930 return this.image;
12931
12932 }
12933
12934 set images( value ) {
12935
12936 this.image = value;
12937
12938 }
12939
12940 }
12941
12943
12944 constructor( size = 1, options = {} ) {
12945
12946 super( size, size, options );
12947
12948 this.isWebGLCubeRenderTarget = true;
12949
12950 const image = { width: size, height: size, depth: 1 };
12951 const images = [ image, image, image, image, image, image ];
12952
12953 if ( options.encoding !== undefined ) {
12954
12955 // @deprecated, r152
12956 warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' );
12957 options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace;
12958
12959 }
12960
12961 this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
12962
12963 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
12964 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
12965 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
12966
12967 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
12968 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture
12969 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).
12970
12971 this.texture.isRenderTargetTexture = true;
12972
12973 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
12974 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
12975
12976 }
12977
12978 fromEquirectangularTexture( renderer, texture ) {
12979
12980 this.texture.type = texture.type;
12981 this.texture.colorSpace = texture.colorSpace;
12982
12983 this.texture.generateMipmaps = texture.generateMipmaps;
12984 this.texture.minFilter = texture.minFilter;
12985 this.texture.magFilter = texture.magFilter;
12986
12987 const shader = {
12988
12989 uniforms: {
12990 tEquirect: { value: null },
12991 },
12992
12993 vertexShader: /* glsl */`
12994
12996
12998
12999 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
13000
13001 }
13002
13003 void main() {
13004
13006
13007 #include <begin_vertex>
13008 #include <project_vertex>
13009
13010 }
13011 `,
13012
13013 fragmentShader: /* glsl */`
13014
13016
13018
13019 #include <common>
13020
13021 void main() {
13022
13024
13026
13028
13029 }
13030 `
13031 };
13032
13033 const geometry = new BoxGeometry( 5, 5, 5 );
13034
13035 const material = new ShaderMaterial( {
13036
13037 name: 'CubemapFromEquirect',
13038
13039 uniforms: cloneUniforms( shader.uniforms ),
13040 vertexShader: shader.vertexShader,
13041 fragmentShader: shader.fragmentShader,
13042 side: BackSide,
13044
13045 } );
13046
13047 material.uniforms.tEquirect.value = texture;
13048
13049 const mesh = new Mesh( geometry, material );
13050
13051 const currentMinFilter = texture.minFilter;
13052
13053 // Avoid blurred poles
13054 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
13055
13056 const camera = new CubeCamera( 1, 10, this );
13057 camera.update( renderer, mesh );
13058
13059 texture.minFilter = currentMinFilter;
13060
13061 mesh.geometry.dispose();
13062 mesh.material.dispose();
13063
13064 return this;
13065
13066 }
13067
13068 clear( renderer, color, depth, stencil ) {
13069
13070 const currentRenderTarget = renderer.getRenderTarget();
13071
13072 for ( let i = 0; i < 6; i ++ ) {
13073
13074 renderer.setRenderTarget( this, i );
13075
13076 renderer.clear( color, depth, stencil );
13077
13078 }
13079
13080 renderer.setRenderTarget( currentRenderTarget );
13081
13082 }
13083
13084 }
13085
13086 const _vector1 = /*@__PURE__*/ new Vector3();
13087 const _vector2 = /*@__PURE__*/ new Vector3();
13088 const _normalMatrix = /*@__PURE__*/ new Matrix3();
13089
13090 class Plane {
13091
13092 constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {
13093
13094 this.isPlane = true;
13095
13096 // normal is assumed to be normalized
13097
13098 this.normal = normal;
13099 this.constant = constant;
13100
13101 }
13102
13103 set( normal, constant ) {
13104
13105 this.normal.copy( normal );
13106 this.constant = constant;
13107
13108 return this;
13109
13110 }
13111
13112 setComponents( x, y, z, w ) {
13113
13114 this.normal.set( x, y, z );
13115 this.constant = w;
13116
13117 return this;
13118
13119 }
13120
13122
13123 this.normal.copy( normal );
13124 this.constant = - point.dot( this.normal );
13125
13126 return this;
13127
13128 }
13129
13130 setFromCoplanarPoints( a, b, c ) {
13131
13132 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();
13133
13134 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
13135
13137
13138 return this;
13139
13140 }
13141
13142 copy( plane ) {
13143
13144 this.normal.copy( plane.normal );
13145 this.constant = plane.constant;
13146
13147 return this;
13148
13149 }
13150
13151 normalize() {
13152
13153 // Note: will lead to a divide by zero if the plane is invalid.
13154
13155 const inverseNormalLength = 1.0 / this.normal.length();
13156 this.normal.multiplyScalar( inverseNormalLength );
13158
13159 return this;
13160
13161 }
13162
13163 negate() {
13164
13165 this.constant *= - 1;
13166 this.normal.negate();
13167
13168 return this;
13169
13170 }
13171
13173
13174 return this.normal.dot( point ) + this.constant;
13175
13176 }
13177
13179
13180 return this.distanceToPoint( sphere.center ) - sphere.radius;
13181
13182 }
13183
13184 projectPoint( point, target ) {
13185
13186 return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) );
13187
13188 }
13189
13190 intersectLine( line, target ) {
13191
13192 const direction = line.delta( _vector1 );
13193
13194 const denominator = this.normal.dot( direction );
13195
13196 if ( denominator === 0 ) {
13197
13198 // line is coplanar, return origin
13199 if ( this.distanceToPoint( line.start ) === 0 ) {
13200
13201 return target.copy( line.start );
13202
13203 }
13204
13205 // Unsure if this is the correct method to handle this case.
13206 return null;
13207
13208 }
13209
13210 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
13211
13212 if ( t < 0 || t > 1 ) {
13213
13214 return null;
13215
13216 }
13217
13218 return target.copy( line.start ).addScaledVector( direction, t );
13219
13220 }
13221
13222 intersectsLine( line ) {
13223
13224 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
13225
13226 const startSign = this.distanceToPoint( line.start );
13227 const endSign = this.distanceToPoint( line.end );
13228
13230
13231 }
13232
13233 intersectsBox( box ) {
13234
13235 return box.intersectsPlane( this );
13236
13237 }
13238
13240
13241 return sphere.intersectsPlane( this );
13242
13243 }
13244
13245 coplanarPoint( target ) {
13246
13247 return target.copy( this.normal ).multiplyScalar( - this.constant );
13248
13249 }
13250
13252
13253 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );
13254
13255 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
13256
13257 const normal = this.normal.applyMatrix3( normalMatrix ).normalize();
13258
13259 this.constant = - referencePoint.dot( normal );
13260
13261 return this;
13262
13263 }
13264
13265 translate( offset ) {
13266
13267 this.constant -= offset.dot( this.normal );
13268
13269 return this;
13270
13271 }
13272
13273 equals( plane ) {
13274
13275 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
13276
13277 }
13278
13279 clone() {
13280
13281 return new this.constructor().copy( this );
13282
13283 }
13284
13285 }
13286
13287 const _sphere$5 = /*@__PURE__*/ new Sphere();
13288 const _vector$7 = /*@__PURE__*/ new Vector3();
13289
13290 class Frustum {
13291
13292 constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {
13293
13294 this.planes = [ p0, p1, p2, p3, p4, p5 ];
13295
13296 }
13297
13298 set( p0, p1, p2, p3, p4, p5 ) {
13299
13300 const planes = this.planes;
13301
13302 planes[ 0 ].copy( p0 );
13303 planes[ 1 ].copy( p1 );
13304 planes[ 2 ].copy( p2 );
13305 planes[ 3 ].copy( p3 );
13306 planes[ 4 ].copy( p4 );
13307 planes[ 5 ].copy( p5 );
13308
13309 return this;
13310
13311 }
13312
13313 copy( frustum ) {
13314
13315 const planes = this.planes;
13316
13317 for ( let i = 0; i < 6; i ++ ) {
13318
13319 planes[ i ].copy( frustum.planes[ i ] );
13320
13321 }
13322
13323 return this;
13324
13325 }
13326
13328
13329 const planes = this.planes;
13330 const me = m.elements;
13331 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
13332 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
13333 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
13334 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
13335
13336 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
13337 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
13338 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
13339 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
13340 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
13341
13343
13344 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
13345
13346 } else if ( coordinateSystem === WebGPUCoordinateSystem ) {
13347
13348 planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();
13349
13350 } else {
13351
13352 throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );
13353
13354 }
13355
13356 return this;
13357
13358 }
13359
13360 intersectsObject( object ) {
13361
13362 if ( object.boundingSphere !== undefined ) {
13363
13364 if ( object.boundingSphere === null ) object.computeBoundingSphere();
13365
13366 _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );
13367
13368 } else {
13369
13370 const geometry = object.geometry;
13371
13372 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
13373
13374 _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
13375
13376 }
13377
13378 return this.intersectsSphere( _sphere$5 );
13379
13380 }
13381
13383
13384 _sphere$5.center.set( 0, 0, 0 );
13385 _sphere$5.radius = 0.7071067811865476;
13386 _sphere$5.applyMatrix4( sprite.matrixWorld );
13387
13388 return this.intersectsSphere( _sphere$5 );
13389
13390 }
13391
13393
13394 const planes = this.planes;
13395 const center = sphere.center;
13396 const negRadius = - sphere.radius;
13397
13398 for ( let i = 0; i < 6; i ++ ) {
13399
13400 const distance = planes[ i ].distanceToPoint( center );
13401
13402 if ( distance < negRadius ) {
13403
13404 return false;
13405
13406 }
13407
13408 }
13409
13410 return true;
13411
13412 }
13413
13414 intersectsBox( box ) {
13415
13416 const planes = this.planes;
13417
13418 for ( let i = 0; i < 6; i ++ ) {
13419
13420 const plane = planes[ i ];
13421
13422 // corner at max distance
13423
13424 _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;
13425 _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;
13426 _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;
13427
13428 if ( plane.distanceToPoint( _vector$7 ) < 0 ) {
13429
13430 return false;
13431
13432 }
13433
13434 }
13435
13436 return true;
13437
13438 }
13439
13440 containsPoint( point ) {
13441
13442 const planes = this.planes;
13443
13444 for ( let i = 0; i < 6; i ++ ) {
13445
13446 if ( planes[ i ].distanceToPoint( point ) < 0 ) {
13447
13448 return false;
13449
13450 }
13451
13452 }
13453
13454 return true;
13455
13456 }
13457
13458 clone() {
13459
13460 return new this.constructor().copy( this );
13461
13462 }
13463
13464 }
13465
13466 function WebGLAnimation() {
13467
13468 let context = null;
13469 let isAnimating = false;
13470 let animationLoop = null;
13471 let requestId = null;
13472
13473 function onAnimationFrame( time, frame ) {
13474
13476
13477 requestId = context.requestAnimationFrame( onAnimationFrame );
13478
13479 }
13480
13481 return {
13482
13483 start: function () {
13484
13485 if ( isAnimating === true ) return;
13486 if ( animationLoop === null ) return;
13487
13488 requestId = context.requestAnimationFrame( onAnimationFrame );
13489
13490 isAnimating = true;
13491
13492 },
13493
13494 stop: function () {
13495
13496 context.cancelAnimationFrame( requestId );
13497
13498 isAnimating = false;
13499
13500 },
13501
13502 setAnimationLoop: function ( callback ) {
13503
13505
13506 },
13507
13508 setContext: function ( value ) {
13509
13510 context = value;
13511
13512 }
13513
13514 };
13515
13516 }
13517
13518 function WebGLAttributes( gl, capabilities ) {
13519
13520 const isWebGL2 = capabilities.isWebGL2;
13521
13522 const buffers = new WeakMap();
13523
13524 function createBuffer( attribute, bufferType ) {
13525
13526 const array = attribute.array;
13527 const usage = attribute.usage;
13528 const size = array.byteLength;
13529
13530 const buffer = gl.createBuffer();
13531
13532 gl.bindBuffer( bufferType, buffer );
13533 gl.bufferData( bufferType, array, usage );
13534
13535 attribute.onUploadCallback();
13536
13537 let type;
13538
13540
13541 type = gl.FLOAT;
13542
13543 } else if ( array instanceof Uint16Array ) {
13544
13545 if ( attribute.isFloat16BufferAttribute ) {
13546
13547 if ( isWebGL2 ) {
13548
13549 type = gl.HALF_FLOAT;
13550
13551 } else {
13552
13553 throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' );
13554
13555 }
13556
13557 } else {
13558
13559 type = gl.UNSIGNED_SHORT;
13560
13561 }
13562
13563 } else if ( array instanceof Int16Array ) {
13564
13565 type = gl.SHORT;
13566
13567 } else if ( array instanceof Uint32Array ) {
13568
13569 type = gl.UNSIGNED_INT;
13570
13571 } else if ( array instanceof Int32Array ) {
13572
13573 type = gl.INT;
13574
13575 } else if ( array instanceof Int8Array ) {
13576
13577 type = gl.BYTE;
13578
13579 } else if ( array instanceof Uint8Array ) {
13580
13581 type = gl.UNSIGNED_BYTE;
13582
13583 } else if ( array instanceof Uint8ClampedArray ) {
13584
13585 type = gl.UNSIGNED_BYTE;
13586
13587 } else {
13588
13589 throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );
13590
13591 }
13592
13593 return {
13594 buffer: buffer,
13595 type: type,
13596 bytesPerElement: array.BYTES_PER_ELEMENT,
13597 version: attribute.version,
13598 size: size
13599 };
13600
13601 }
13602
13603 function updateBuffer( buffer, attribute, bufferType ) {
13604
13605 const array = attribute.array;
13606 const updateRange = attribute._updateRange; // deprecated
13607 const updateRanges = attribute.updateRanges;
13608
13609 gl.bindBuffer( bufferType, buffer );
13610
13611 if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
13612
13613 // Not using update ranges
13614 gl.bufferSubData( bufferType, 0, array );
13615
13616 }
13617
13618 if ( updateRanges.length !== 0 ) {
13619
13620 for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
13621
13622 const range = updateRanges[ i ];
13623 if ( isWebGL2 ) {
13624
13625 gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13626 array, range.start, range.count );
13627
13628 } else {
13629
13630 gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
13631 array.subarray( range.start, range.start + range.count ) );
13632
13633 }
13634
13635 }
13636
13637 attribute.clearUpdateRanges();
13638
13639 }
13640
13641 // deprecated
13642 if ( updateRange.count !== - 1 ) {
13643
13644 if ( isWebGL2 ) {
13645
13646 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13647 array, updateRange.offset, updateRange.count );
13648
13649 } else {
13650
13651 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
13652 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
13653
13654 }
13655
13656 updateRange.count = - 1; // reset range
13657
13658 }
13659
13660 attribute.onUploadCallback();
13661
13662 }
13663
13664 //
13665
13666 function get( attribute ) {
13667
13668 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13669
13670 return buffers.get( attribute );
13671
13672 }
13673
13674 function remove( attribute ) {
13675
13676 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13677
13678 const data = buffers.get( attribute );
13679
13680 if ( data ) {
13681
13682 gl.deleteBuffer( data.buffer );
13683
13684 buffers.delete( attribute );
13685
13686 }
13687
13688 }
13689
13690 function update( attribute, bufferType ) {
13691
13692 if ( attribute.isGLBufferAttribute ) {
13693
13694 const cached = buffers.get( attribute );
13695
13696 if ( ! cached || cached.version < attribute.version ) {
13697
13698 buffers.set( attribute, {
13699 buffer: attribute.buffer,
13700 type: attribute.type,
13701 bytesPerElement: attribute.elementSize,
13702 version: attribute.version
13703 } );
13704
13705 }
13706
13707 return;
13708
13709 }
13710
13711 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
13712
13713 const data = buffers.get( attribute );
13714
13715 if ( data === undefined ) {
13716
13718
13719 } else if ( data.version < attribute.version ) {
13720
13721 if ( data.size !== attribute.array.byteLength ) {
13722
13723 throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' );
13724
13725 }
13726
13728
13729 data.version = attribute.version;
13730
13731 }
13732
13733 }
13734
13735 return {
13736
13737 get: get,
13738 remove: remove,
13739 update: update
13740
13741 };
13742
13743 }
13744
13745 class PlaneGeometry extends BufferGeometry {
13746
13747 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {
13748
13749 super();
13750
13751 this.type = 'PlaneGeometry';
13752
13753 this.parameters = {
13754 width: width,
13755 height: height,
13758 };
13759
13760 const width_half = width / 2;
13761 const height_half = height / 2;
13762
13763 const gridX = Math.floor( widthSegments );
13764 const gridY = Math.floor( heightSegments );
13765
13766 const gridX1 = gridX + 1;
13767 const gridY1 = gridY + 1;
13768
13769 const segment_width = width / gridX;
13770 const segment_height = height / gridY;
13771
13772 //
13773
13774 const indices = [];
13775 const vertices = [];
13776 const normals = [];
13777 const uvs = [];
13778
13779 for ( let iy = 0; iy < gridY1; iy ++ ) {
13780
13781 const y = iy * segment_height - height_half;
13782
13783 for ( let ix = 0; ix < gridX1; ix ++ ) {
13784
13785 const x = ix * segment_width - width_half;
13786
13787 vertices.push( x, - y, 0 );
13788
13789 normals.push( 0, 0, 1 );
13790
13791 uvs.push( ix / gridX );
13792 uvs.push( 1 - ( iy / gridY ) );
13793
13794 }
13795
13796 }
13797
13798 for ( let iy = 0; iy < gridY; iy ++ ) {
13799
13800 for ( let ix = 0; ix < gridX; ix ++ ) {
13801
13802 const a = ix + gridX1 * iy;
13803 const b = ix + gridX1 * ( iy + 1 );
13804 const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
13805 const d = ( ix + 1 ) + gridX1 * iy;
13806
13807 indices.push( a, b, d );
13808 indices.push( b, c, d );
13809
13810 }
13811
13812 }
13813
13814 this.setIndex( indices );
13815 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
13816 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
13817 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
13818
13819 }
13820
13821 copy( source ) {
13822
13823 super.copy( source );
13824
13825 this.parameters = Object.assign( {}, source.parameters );
13826
13827 return this;
13828
13829 }
13830
13831 static fromJSON( data ) {
13832
13833 return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );
13834
13835 }
13836
13837 }
13838
13839 var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif";
13840
13841 var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif";
13842
13843 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif";
13844
13845 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
13846
13847 var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif";
13848
13849 var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif";
13850
13851 var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif";
13852
13853 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
13854
13855 var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif";
13856
13857 var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif";
13858
13859 var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif";
13860
13861 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
13862
13863 var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated";
13864
13865 var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif";
13866
13867 var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif";
13868
13869 var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
13870
13871 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
13872
13873 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
13874
13875 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
13876
13877 var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif";
13878
13879 var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif";
13880
13881 var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
13882
13883 var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
13884
13885 var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated";
13886
13887 var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif";
13888
13889 var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
13890
13891 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
13892
13893 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif";
13894
13895 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
13896
13897 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
13898
13899 var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
13900
13901 var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}";
13902
13903 var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif";
13904
13905 var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif";
13906
13907 var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif";
13908
13909 var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif";
13910
13911 var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif";
13912
13913 var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif";
13914
13915 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif";
13916
13917 var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif";
13918
13919 var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif";
13920
13921 var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}";
13922
13923 var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif";
13924
13925 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
13926
13927 var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;";
13928
13929 var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert";
13930
13931 var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif";
13932
13933 var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif";
13934
13935 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
13936
13937 var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon";
13938
13939 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
13940
13941 var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong";
13942
13943 var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif";
13944
13945 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
13946
13947 var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
13948
13949 var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif";
13950
13951 var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif";
13952
13953 var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
13954
13955 var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
13956
13957 var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif";
13958
13959 var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
13960
13961 var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif";
13962
13963 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
13964
13965 var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif";
13966
13967 var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
13968
13969 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
13970
13971 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
13972
13973 var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif";
13974
13975 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif";
13976
13977 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif";
13978
13979 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif";
13980
13981 var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;";
13982
13983 var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
13984
13985 var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
13986
13987 var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
13988
13989 var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif";
13990
13991 var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif";
13992
13993 var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif";
13994
13995 var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif";
13996
13997 var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif";
13998
13999 var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif";
14000
14001 var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );";
14002
14003 var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}";
14004
14005 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
14006
14007 var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;";
14008
14009 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
14010
14011 var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif";
14012
14013 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
14014
14015 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
14016
14017 var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif";
14018
14019 var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
14020
14021 var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif";
14022
14023 var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
14024
14025 var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
14026
14027 var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif";
14028
14029 var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif";
14030
14031 var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif";
14032
14033 var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
14034
14035 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
14036
14037 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
14038
14039 var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
14040
14041 var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif";
14042
14043 var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif";
14044
14045 var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif";
14046
14047 var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif";
14048
14049 var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif";
14050
14051 var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif";
14052
14053 const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
14054
14055 const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
14056
14057 const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
14058
14059 const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
14060
14061 const vertex$f = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
14062
14063 const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
14064
14065 const vertex$e = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvHighPrecisionZW = gl_Position.zw;\n}";
14066
14067 const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <logdepthbuf_fragment>\n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}";
14068
14069 const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}";
14070
14071 const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}";
14072
14073 const vertex$c = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}";
14074
14075 const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
14076
14077 const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
14078
14079 const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
14080
14081 const vertex$a = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinbase_vertex>\n\t\t#include <skinnormal_vertex>\n\t\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}";
14082
14083 const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14084
14085 const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
14086
14087 const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_lambert_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_lambert_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14088
14089 const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}";
14090
14091 const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14092
14093 const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}";
14094
14095 const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}";
14096
14097 const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
14098
14099 const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14100
14101 const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}";
14102
14103 const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <iridescence_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_physical_pars_fragment>\n#include <transmission_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_pars_fragment>\n#include <iridescence_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include <transmission_fragment>\n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14104
14105 const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
14106
14107 const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}";
14108
14109 const vertex$3 = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}";
14110
14111 const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}";
14112
14113 const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}";
14114
14115 const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
14116
14117 const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
14118
14119 const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
14120
14121 const ShaderChunk = {
14134 bsdfs: bsdfs,
14145 common: common,
14229
14264 };
14265
14270 const UniformsLib = {
14271
14272 common: {
14273
14274 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14275 opacity: { value: 1.0 },
14276
14277 map: { value: null },
14278 mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14279
14280 alphaMap: { value: null },
14281 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14282
14283 alphaTest: { value: 0 }
14284
14285 },
14286
14287 specularmap: {
14288
14289 specularMap: { value: null },
14290 specularMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14291
14292 },
14293
14294 envmap: {
14295
14296 envMap: { value: null },
14297 flipEnvMap: { value: - 1 },
14298 reflectivity: { value: 1.0 }, // basic, lambert, phong
14299 ior: { value: 1.5 }, // physical
14300 refractionRatio: { value: 0.98 }, // basic, lambert, phong
14301
14302 },
14303
14304 aomap: {
14305
14306 aoMap: { value: null },
14307 aoMapIntensity: { value: 1 },
14308 aoMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14309
14310 },
14311
14312 lightmap: {
14313
14314 lightMap: { value: null },
14315 lightMapIntensity: { value: 1 },
14316 lightMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14317
14318 },
14319
14320 bumpmap: {
14321
14322 bumpMap: { value: null },
14323 bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14324 bumpScale: { value: 1 }
14325
14326 },
14327
14328 normalmap: {
14329
14330 normalMap: { value: null },
14331 normalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14332 normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }
14333
14334 },
14335
14337
14338 displacementMap: { value: null },
14339 displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14340 displacementScale: { value: 1 },
14341 displacementBias: { value: 0 }
14342
14343 },
14344
14345 emissivemap: {
14346
14347 emissiveMap: { value: null },
14348 emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14349
14350 },
14351
14352 metalnessmap: {
14353
14354 metalnessMap: { value: null },
14355 metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14356
14357 },
14358
14359 roughnessmap: {
14360
14361 roughnessMap: { value: null },
14362 roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }
14363
14364 },
14365
14366 gradientmap: {
14367
14368 gradientMap: { value: null }
14369
14370 },
14371
14372 fog: {
14373
14374 fogDensity: { value: 0.00025 },
14375 fogNear: { value: 1 },
14376 fogFar: { value: 2000 },
14377 fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }
14378
14379 },
14380
14381 lights: {
14382
14383 ambientLightColor: { value: [] },
14384
14385 lightProbe: { value: [] },
14386
14387 directionalLights: { value: [], properties: {
14388 direction: {},
14389 color: {}
14390 } },
14391
14392 directionalLightShadows: { value: [], properties: {
14393 shadowBias: {},
14394 shadowNormalBias: {},
14395 shadowRadius: {},
14396 shadowMapSize: {}
14397 } },
14398
14399 directionalShadowMap: { value: [] },
14401
14402 spotLights: { value: [], properties: {
14403 color: {},
14404 position: {},
14405 direction: {},
14406 distance: {},
14407 coneCos: {},
14408 penumbraCos: {},
14409 decay: {}
14410 } },
14411
14412 spotLightShadows: { value: [], properties: {
14413 shadowBias: {},
14414 shadowNormalBias: {},
14415 shadowRadius: {},
14416 shadowMapSize: {}
14417 } },
14418
14419 spotLightMap: { value: [] },
14420 spotShadowMap: { value: [] },
14421 spotLightMatrix: { value: [] },
14422
14423 pointLights: { value: [], properties: {
14424 color: {},
14425 position: {},
14426 decay: {},
14427 distance: {}
14428 } },
14429
14430 pointLightShadows: { value: [], properties: {
14431 shadowBias: {},
14432 shadowNormalBias: {},
14433 shadowRadius: {},
14434 shadowMapSize: {},
14435 shadowCameraNear: {},
14436 shadowCameraFar: {}
14437 } },
14438
14439 pointShadowMap: { value: [] },
14440 pointShadowMatrix: { value: [] },
14441
14442 hemisphereLights: { value: [], properties: {
14443 direction: {},
14444 skyColor: {},
14445 groundColor: {}
14446 } },
14447
14448 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
14449 rectAreaLights: { value: [], properties: {
14450 color: {},
14451 position: {},
14452 width: {},
14453 height: {}
14454 } },
14455
14456 ltc_1: { value: null },
14457 ltc_2: { value: null }
14458
14459 },
14460
14461 points: {
14462
14463 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14464 opacity: { value: 1.0 },
14465 size: { value: 1.0 },
14466 scale: { value: 1.0 },
14467 map: { value: null },
14468 alphaMap: { value: null },
14469 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14470 alphaTest: { value: 0 },
14471 uvTransform: { value: /*@__PURE__*/ new Matrix3() }
14472
14473 },
14474
14475 sprite: {
14476
14477 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },
14478 opacity: { value: 1.0 },
14479 center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },
14480 rotation: { value: 0.0 },
14481 map: { value: null },
14482 mapTransform: { value: /*@__PURE__*/ new Matrix3() },
14483 alphaMap: { value: null },
14484 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14485 alphaTest: { value: 0 }
14486
14487 }
14488
14489 };
14490
14491 const ShaderLib = {
14492
14493 basic: {
14494
14495 uniforms: /*@__PURE__*/ mergeUniforms( [
14496 UniformsLib.common,
14497 UniformsLib.specularmap,
14498 UniformsLib.envmap,
14499 UniformsLib.aomap,
14500 UniformsLib.lightmap,
14501 UniformsLib.fog
14502 ] ),
14503
14504 vertexShader: ShaderChunk.meshbasic_vert,
14505 fragmentShader: ShaderChunk.meshbasic_frag
14506
14507 },
14508
14509 lambert: {
14510
14511 uniforms: /*@__PURE__*/ mergeUniforms( [
14512 UniformsLib.common,
14513 UniformsLib.specularmap,
14514 UniformsLib.envmap,
14515 UniformsLib.aomap,
14516 UniformsLib.lightmap,
14517 UniformsLib.emissivemap,
14518 UniformsLib.bumpmap,
14519 UniformsLib.normalmap,
14520 UniformsLib.displacementmap,
14521 UniformsLib.fog,
14522 UniformsLib.lights,
14523 {
14524 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14525 }
14526 ] ),
14527
14530
14531 },
14532
14533 phong: {
14534
14535 uniforms: /*@__PURE__*/ mergeUniforms( [
14536 UniformsLib.common,
14537 UniformsLib.specularmap,
14538 UniformsLib.envmap,
14539 UniformsLib.aomap,
14540 UniformsLib.lightmap,
14541 UniformsLib.emissivemap,
14542 UniformsLib.bumpmap,
14543 UniformsLib.normalmap,
14544 UniformsLib.displacementmap,
14545 UniformsLib.fog,
14546 UniformsLib.lights,
14547 {
14548 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14549 specular: { value: /*@__PURE__*/ new Color( 0x111111 ) },
14550 shininess: { value: 30 }
14551 }
14552 ] ),
14553
14556
14557 },
14558
14559 standard: {
14560
14561 uniforms: /*@__PURE__*/ mergeUniforms( [
14562 UniformsLib.common,
14563 UniformsLib.envmap,
14564 UniformsLib.aomap,
14565 UniformsLib.lightmap,
14566 UniformsLib.emissivemap,
14567 UniformsLib.bumpmap,
14568 UniformsLib.normalmap,
14569 UniformsLib.displacementmap,
14570 UniformsLib.roughnessmap,
14571 UniformsLib.metalnessmap,
14572 UniformsLib.fog,
14573 UniformsLib.lights,
14574 {
14575 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14576 roughness: { value: 1.0 },
14577 metalness: { value: 0.0 },
14578 envMapIntensity: { value: 1 } // temporary
14579 }
14580 ] ),
14581
14584
14585 },
14586
14587 toon: {
14588
14589 uniforms: /*@__PURE__*/ mergeUniforms( [
14590 UniformsLib.common,
14591 UniformsLib.aomap,
14592 UniformsLib.lightmap,
14593 UniformsLib.emissivemap,
14594 UniformsLib.bumpmap,
14595 UniformsLib.normalmap,
14596 UniformsLib.displacementmap,
14597 UniformsLib.gradientmap,
14598 UniformsLib.fog,
14599 UniformsLib.lights,
14600 {
14601 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }
14602 }
14603 ] ),
14604
14607
14608 },
14609
14610 matcap: {
14611
14612 uniforms: /*@__PURE__*/ mergeUniforms( [
14613 UniformsLib.common,
14614 UniformsLib.bumpmap,
14615 UniformsLib.normalmap,
14616 UniformsLib.displacementmap,
14617 UniformsLib.fog,
14618 {
14619 matcap: { value: null }
14620 }
14621 ] ),
14622
14625
14626 },
14627
14628 points: {
14629
14630 uniforms: /*@__PURE__*/ mergeUniforms( [
14631 UniformsLib.points,
14632 UniformsLib.fog
14633 ] ),
14634
14635 vertexShader: ShaderChunk.points_vert,
14636 fragmentShader: ShaderChunk.points_frag
14637
14638 },
14639
14640 dashed: {
14641
14642 uniforms: /*@__PURE__*/ mergeUniforms( [
14643 UniformsLib.common,
14644 UniformsLib.fog,
14645 {
14646 scale: { value: 1 },
14647 dashSize: { value: 1 },
14648 totalSize: { value: 2 }
14649 }
14650 ] ),
14651
14654
14655 },
14656
14657 depth: {
14658
14659 uniforms: /*@__PURE__*/ mergeUniforms( [
14660 UniformsLib.common,
14661 UniformsLib.displacementmap
14662 ] ),
14663
14664 vertexShader: ShaderChunk.depth_vert,
14665 fragmentShader: ShaderChunk.depth_frag
14666
14667 },
14668
14669 normal: {
14670
14671 uniforms: /*@__PURE__*/ mergeUniforms( [
14672 UniformsLib.common,
14673 UniformsLib.bumpmap,
14674 UniformsLib.normalmap,
14675 UniformsLib.displacementmap,
14676 {
14677 opacity: { value: 1.0 }
14678 }
14679 ] ),
14680
14683
14684 },
14685
14686 sprite: {
14687
14688 uniforms: /*@__PURE__*/ mergeUniforms( [
14689 UniformsLib.sprite,
14690 UniformsLib.fog
14691 ] ),
14692
14693 vertexShader: ShaderChunk.sprite_vert,
14694 fragmentShader: ShaderChunk.sprite_frag
14695
14696 },
14697
14698 background: {
14699
14700 uniforms: {
14701 uvTransform: { value: /*@__PURE__*/ new Matrix3() },
14702 t2D: { value: null },
14704 },
14705
14706 vertexShader: ShaderChunk.background_vert,
14707 fragmentShader: ShaderChunk.background_frag
14708
14709 },
14710
14712
14713 uniforms: {
14714 envMap: { value: null },
14715 flipEnvMap: { value: - 1 },
14718 },
14719
14720 vertexShader: ShaderChunk.backgroundCube_vert,
14721 fragmentShader: ShaderChunk.backgroundCube_frag
14722
14723 },
14724
14725 cube: {
14726
14727 uniforms: {
14728 tCube: { value: null },
14729 tFlip: { value: - 1 },
14730 opacity: { value: 1.0 }
14731 },
14732
14733 vertexShader: ShaderChunk.cube_vert,
14734 fragmentShader: ShaderChunk.cube_frag
14735
14736 },
14737
14738 equirect: {
14739
14740 uniforms: {
14741 tEquirect: { value: null },
14742 },
14743
14744 vertexShader: ShaderChunk.equirect_vert,
14745 fragmentShader: ShaderChunk.equirect_frag
14746
14747 },
14748
14749 distanceRGBA: {
14750
14751 uniforms: /*@__PURE__*/ mergeUniforms( [
14752 UniformsLib.common,
14753 UniformsLib.displacementmap,
14754 {
14755 referencePosition: { value: /*@__PURE__*/ new Vector3() },
14756 nearDistance: { value: 1 },
14757 farDistance: { value: 1000 }
14758 }
14759 ] ),
14760
14763
14764 },
14765
14766 shadow: {
14767
14768 uniforms: /*@__PURE__*/ mergeUniforms( [
14769 UniformsLib.lights,
14770 UniformsLib.fog,
14771 {
14772 color: { value: /*@__PURE__*/ new Color( 0x00000 ) },
14773 opacity: { value: 1.0 }
14774 },
14775 ] ),
14776
14779
14780 }
14781
14782 };
14783
14784 ShaderLib.physical = {
14785
14786 uniforms: /*@__PURE__*/ mergeUniforms( [
14787 ShaderLib.standard.uniforms,
14788 {
14789 clearcoat: { value: 0 },
14790 clearcoatMap: { value: null },
14791 clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14792 clearcoatNormalMap: { value: null },
14793 clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14794 clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },
14795 clearcoatRoughness: { value: 0 },
14796 clearcoatRoughnessMap: { value: null },
14797 clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14798 iridescence: { value: 0 },
14799 iridescenceMap: { value: null },
14800 iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14801 iridescenceIOR: { value: 1.3 },
14804 iridescenceThicknessMap: { value: null },
14805 iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14806 sheen: { value: 0 },
14807 sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14808 sheenColorMap: { value: null },
14809 sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14810 sheenRoughness: { value: 1 },
14811 sheenRoughnessMap: { value: null },
14812 sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14813 transmission: { value: 0 },
14814 transmissionMap: { value: null },
14815 transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14816 transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },
14817 transmissionSamplerMap: { value: null },
14818 thickness: { value: 0 },
14819 thicknessMap: { value: null },
14820 thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14821 attenuationDistance: { value: 0 },
14822 attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },
14823 specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },
14824 specularColorMap: { value: null },
14825 specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14826 specularIntensity: { value: 1 },
14827 specularIntensityMap: { value: null },
14828 specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14829 anisotropyVector: { value: /*@__PURE__*/ new Vector2() },
14830 anisotropyMap: { value: null },
14831 anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },
14832 }
14833 ] ),
14834
14837
14838 };
14839
14840 const _rgb = { r: 0, b: 0, g: 0 };
14841
14843
14844 const clearColor = new Color( 0x000000 );
14845 let clearAlpha = alpha === true ? 0 : 1;
14846
14847 let planeMesh;
14848 let boxMesh;
14849
14850 let currentBackground = null;
14852 let currentTonemapping = null;
14853
14854 function render( renderList, scene ) {
14855
14856 let forceClear = false;
14857 let background = scene.isScene === true ? scene.background : null;
14858
14859 if ( background && background.isTexture ) {
14860
14861 const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background
14863
14864 }
14865
14866 if ( background === null ) {
14867
14869
14870 } else if ( background && background.isColor ) {
14871
14872 setClear( background, 1 );
14873 forceClear = true;
14874
14875 }
14876
14877 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();
14878
14879 if ( environmentBlendMode === 'additive' ) {
14880
14881 state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
14882
14883 } else if ( environmentBlendMode === 'alpha-blend' ) {
14884
14885 state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
14886
14887 }
14888
14889 if ( renderer.autoClear || forceClear ) {
14890
14891 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
14892
14893 }
14894
14895 if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {
14896
14897 if ( boxMesh === undefined ) {
14898
14899 boxMesh = new Mesh(
14900 new BoxGeometry( 1, 1, 1 ),
14901 new ShaderMaterial( {
14902 name: 'BackgroundCubeMaterial',
14903 uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
14904 vertexShader: ShaderLib.backgroundCube.vertexShader,
14905 fragmentShader: ShaderLib.backgroundCube.fragmentShader,
14906 side: BackSide,
14907 depthTest: false,
14908 depthWrite: false,
14909 fog: false
14910 } )
14911 );
14912
14913 boxMesh.geometry.deleteAttribute( 'normal' );
14914 boxMesh.geometry.deleteAttribute( 'uv' );
14915
14916 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
14917
14918 this.matrixWorld.copyPosition( camera.matrixWorld );
14919
14920 };
14921
14922 // add "envMap" material property so the renderer can evaluate it like for built-in materials
14923 Object.defineProperty( boxMesh.material, 'envMap', {
14924
14925 get: function () {
14926
14927 return this.uniforms.envMap.value;
14928
14929 }
14930
14931 } );
14932
14933 objects.update( boxMesh );
14934
14935 }
14936
14937 boxMesh.material.uniforms.envMap.value = background;
14938 boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;
14939 boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
14940 boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
14941 boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14942
14943 if ( currentBackground !== background ||
14945 currentTonemapping !== renderer.toneMapping ) {
14946
14947 boxMesh.material.needsUpdate = true;
14948
14951 currentTonemapping = renderer.toneMapping;
14952
14953 }
14954
14955 boxMesh.layers.enableAll();
14956
14957 // push to the pre-sorted opaque render list
14958 renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
14959
14960 } else if ( background && background.isTexture ) {
14961
14962 if ( planeMesh === undefined ) {
14963
14964 planeMesh = new Mesh(
14965 new PlaneGeometry( 2, 2 ),
14966 new ShaderMaterial( {
14967 name: 'BackgroundMaterial',
14968 uniforms: cloneUniforms( ShaderLib.background.uniforms ),
14969 vertexShader: ShaderLib.background.vertexShader,
14970 fragmentShader: ShaderLib.background.fragmentShader,
14971 side: FrontSide,
14972 depthTest: false,
14973 depthWrite: false,
14974 fog: false
14975 } )
14976 );
14977
14978 planeMesh.geometry.deleteAttribute( 'normal' );
14979
14980 // add "map" material property so the renderer can evaluate it like for built-in materials
14981 Object.defineProperty( planeMesh.material, 'map', {
14982
14983 get: function () {
14984
14985 return this.uniforms.t2D.value;
14986
14987 }
14988
14989 } );
14990
14991 objects.update( planeMesh );
14992
14993 }
14994
14995 planeMesh.material.uniforms.t2D.value = background;
14996 planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
14997 planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
14998
14999 if ( background.matrixAutoUpdate === true ) {
15000
15001 background.updateMatrix();
15002
15003 }
15004
15005 planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
15006
15007 if ( currentBackground !== background ||
15009 currentTonemapping !== renderer.toneMapping ) {
15010
15011 planeMesh.material.needsUpdate = true;
15012
15015 currentTonemapping = renderer.toneMapping;
15016
15017 }
15018
15019 planeMesh.layers.enableAll();
15020
15021 // push to the pre-sorted opaque render list
15022 renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
15023
15024 }
15025
15026 }
15027
15028 function setClear( color, alpha ) {
15029
15030 color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );
15031
15032 state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );
15033
15034 }
15035
15036 return {
15037
15038 getClearColor: function () {
15039
15040 return clearColor;
15041
15042 },
15043 setClearColor: function ( color, alpha = 1 ) {
15044
15045 clearColor.set( color );
15046 clearAlpha = alpha;
15048
15049 },
15050 getClearAlpha: function () {
15051
15052 return clearAlpha;
15053
15054 },
15055 setClearAlpha: function ( alpha ) {
15056
15057 clearAlpha = alpha;
15059
15060 },
15061 render: render
15062
15063 };
15064
15065 }
15066
15068
15069 const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15070
15071 const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' );
15072 const vaoAvailable = capabilities.isWebGL2 || extension !== null;
15073
15074 const bindingStates = {};
15075
15076 const defaultState = createBindingState( null );
15078 let forceUpdate = false;
15079
15080 function setup( object, material, program, geometry, index ) {
15081
15082 let updateBuffers = false;
15083
15084 if ( vaoAvailable ) {
15085
15087
15088 if ( currentState !== state ) {
15089
15092
15093 }
15094
15096
15097 if ( updateBuffers ) saveCache( object, geometry, program, index );
15098
15099 } else {
15100
15101 const wireframe = ( material.wireframe === true );
15102
15103 if ( currentState.geometry !== geometry.id ||
15104 currentState.program !== program.id ||
15105 currentState.wireframe !== wireframe ) {
15106
15107 currentState.geometry = geometry.id;
15108 currentState.program = program.id;
15109 currentState.wireframe = wireframe;
15110
15111 updateBuffers = true;
15112
15113 }
15114
15115 }
15116
15117 if ( index !== null ) {
15118
15119 attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
15120
15121 }
15122
15123 if ( updateBuffers || forceUpdate ) {
15124
15125 forceUpdate = false;
15126
15128
15129 if ( index !== null ) {
15130
15131 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );
15132
15133 }
15134
15135 }
15136
15137 }
15138
15139 function createVertexArrayObject() {
15140
15141 if ( capabilities.isWebGL2 ) return gl.createVertexArray();
15142
15143 return extension.createVertexArrayOES();
15144
15145 }
15146
15147 function bindVertexArrayObject( vao ) {
15148
15149 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao );
15150
15151 return extension.bindVertexArrayOES( vao );
15152
15153 }
15154
15155 function deleteVertexArrayObject( vao ) {
15156
15157 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao );
15158
15159 return extension.deleteVertexArrayOES( vao );
15160
15161 }
15162
15164
15165 const wireframe = ( material.wireframe === true );
15166
15168
15169 if ( programMap === undefined ) {
15170
15171 programMap = {};
15173
15174 }
15175
15177
15178 if ( stateMap === undefined ) {
15179
15180 stateMap = {};
15181 programMap[ program.id ] = stateMap;
15182
15183 }
15184
15186
15187 if ( state === undefined ) {
15188
15191
15192 }
15193
15194 return state;
15195
15196 }
15197
15198 function createBindingState( vao ) {
15199
15200 const newAttributes = [];
15201 const enabledAttributes = [];
15202 const attributeDivisors = [];
15203
15204 for ( let i = 0; i < maxVertexAttributes; i ++ ) {
15205
15206 newAttributes[ i ] = 0;
15207 enabledAttributes[ i ] = 0;
15208 attributeDivisors[ i ] = 0;
15209
15210 }
15211
15212 return {
15213
15214 // for backward compatibility on non-VAO support browser
15215 geometry: null,
15216 program: null,
15217 wireframe: false,
15218
15222 object: vao,
15223 attributes: {},
15224 index: null
15225
15226 };
15227
15228 }
15229
15230 function needsUpdate( object, geometry, program, index ) {
15231
15232 const cachedAttributes = currentState.attributes;
15233 const geometryAttributes = geometry.attributes;
15234
15235 let attributesNum = 0;
15236
15237 const programAttributes = program.getAttributes();
15238
15239 for ( const name in programAttributes ) {
15240
15242
15243 if ( programAttribute.location >= 0 ) {
15244
15247
15248 if ( geometryAttribute === undefined ) {
15249
15250 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15251 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15252
15253 }
15254
15255 if ( cachedAttribute === undefined ) return true;
15256
15257 if ( cachedAttribute.attribute !== geometryAttribute ) return true;
15258
15259 if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;
15260
15261 attributesNum ++;
15262
15263 }
15264
15265 }
15266
15267 if ( currentState.attributesNum !== attributesNum ) return true;
15268
15269 if ( currentState.index !== index ) return true;
15270
15271 return false;
15272
15273 }
15274
15275 function saveCache( object, geometry, program, index ) {
15276
15277 const cache = {};
15278 const attributes = geometry.attributes;
15279 let attributesNum = 0;
15280
15281 const programAttributes = program.getAttributes();
15282
15283 for ( const name in programAttributes ) {
15284
15286
15287 if ( programAttribute.location >= 0 ) {
15288
15290
15291 if ( attribute === undefined ) {
15292
15293 if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;
15294 if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;
15295
15296 }
15297
15298 const data = {};
15299 data.attribute = attribute;
15300
15301 if ( attribute && attribute.data ) {
15302
15303 data.data = attribute.data;
15304
15305 }
15306
15307 cache[ name ] = data;
15308
15309 attributesNum ++;
15310
15311 }
15312
15313 }
15314
15315 currentState.attributes = cache;
15316 currentState.attributesNum = attributesNum;
15317
15318 currentState.index = index;
15319
15320 }
15321
15322 function initAttributes() {
15323
15324 const newAttributes = currentState.newAttributes;
15325
15326 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {
15327
15328 newAttributes[ i ] = 0;
15329
15330 }
15331
15332 }
15333
15334 function enableAttribute( attribute ) {
15335
15337
15338 }
15339
15341
15342 const newAttributes = currentState.newAttributes;
15343 const enabledAttributes = currentState.enabledAttributes;
15344 const attributeDivisors = currentState.attributeDivisors;
15345
15346 newAttributes[ attribute ] = 1;
15347
15348 if ( enabledAttributes[ attribute ] === 0 ) {
15349
15350 gl.enableVertexAttribArray( attribute );
15352
15353 }
15354
15356
15357 const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' );
15358
15359 extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute );
15361
15362 }
15363
15364 }
15365
15366 function disableUnusedAttributes() {
15367
15368 const newAttributes = currentState.newAttributes;
15369 const enabledAttributes = currentState.enabledAttributes;
15370
15371 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {
15372
15373 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
15374
15375 gl.disableVertexAttribArray( i );
15376 enabledAttributes[ i ] = 0;
15377
15378 }
15379
15380 }
15381
15382 }
15383
15385
15386 if ( integer === true ) {
15387
15388 gl.vertexAttribIPointer( index, size, type, stride, offset );
15389
15390 } else {
15391
15392 gl.vertexAttribPointer( index, size, type, normalized, stride, offset );
15393
15394 }
15395
15396 }
15397
15398 function setupVertexAttributes( object, material, program, geometry ) {
15399
15400 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) {
15401
15402 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return;
15403
15404 }
15405
15407
15408 const geometryAttributes = geometry.attributes;
15409
15410 const programAttributes = program.getAttributes();
15411
15412 const materialDefaultAttributeValues = material.defaultAttributeValues;
15413
15414 for ( const name in programAttributes ) {
15415
15417
15418 if ( programAttribute.location >= 0 ) {
15419
15421
15422 if ( geometryAttribute === undefined ) {
15423
15424 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
15425 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;
15426
15427 }
15428
15429 if ( geometryAttribute !== undefined ) {
15430
15431 const normalized = geometryAttribute.normalized;
15432 const size = geometryAttribute.itemSize;
15433
15434 const attribute = attributes.get( geometryAttribute );
15435
15436 // TODO Attribute may not be available on context restore
15437
15438 if ( attribute === undefined ) continue;
15439
15440 const buffer = attribute.buffer;
15441 const type = attribute.type;
15442 const bytesPerElement = attribute.bytesPerElement;
15443
15444 // check for integer attributes (WebGL 2 only)
15445
15446 const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) );
15447
15448 if ( geometryAttribute.isInterleavedBufferAttribute ) {
15449
15450 const data = geometryAttribute.data;
15451 const stride = data.stride;
15452 const offset = geometryAttribute.offset;
15453
15454 if ( data.isInstancedInterleavedBuffer ) {
15455
15456 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15457
15458 enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );
15459
15460 }
15461
15462 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15463
15464 geometry._maxInstanceCount = data.meshPerAttribute * data.count;
15465
15466 }
15467
15468 } else {
15469
15470 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15471
15472 enableAttribute( programAttribute.location + i );
15473
15474 }
15475
15476 }
15477
15478 gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15479
15480 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15481
15483 programAttribute.location + i,
15484 size / programAttribute.locationSize,
15485 type,
15486 normalized,
15488 ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,
15489 integer
15490 );
15491
15492 }
15493
15494 } else {
15495
15496 if ( geometryAttribute.isInstancedBufferAttribute ) {
15497
15498 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15499
15500 enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );
15501
15502 }
15503
15504 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {
15505
15506 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
15507
15508 }
15509
15510 } else {
15511
15512 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15513
15514 enableAttribute( programAttribute.location + i );
15515
15516 }
15517
15518 }
15519
15520 gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
15521
15522 for ( let i = 0; i < programAttribute.locationSize; i ++ ) {
15523
15525 programAttribute.location + i,
15526 size / programAttribute.locationSize,
15527 type,
15528 normalized,
15530 ( size / programAttribute.locationSize ) * i * bytesPerElement,
15531 integer
15532 );
15533
15534 }
15535
15536 }
15537
15538 } else if ( materialDefaultAttributeValues !== undefined ) {
15539
15541
15542 if ( value !== undefined ) {
15543
15544 switch ( value.length ) {
15545
15546 case 2:
15547 gl.vertexAttrib2fv( programAttribute.location, value );
15548 break;
15549
15550 case 3:
15551 gl.vertexAttrib3fv( programAttribute.location, value );
15552 break;
15553
15554 case 4:
15555 gl.vertexAttrib4fv( programAttribute.location, value );
15556 break;
15557
15558 default:
15559 gl.vertexAttrib1fv( programAttribute.location, value );
15560
15561 }
15562
15563 }
15564
15565 }
15566
15567 }
15568
15569 }
15570
15572
15573 }
15574
15575 function dispose() {
15576
15577 reset();
15578
15579 for ( const geometryId in bindingStates ) {
15580
15582
15583 for ( const programId in programMap ) {
15584
15585 const stateMap = programMap[ programId ];
15586
15587 for ( const wireframe in stateMap ) {
15588
15590
15591 delete stateMap[ wireframe ];
15592
15593 }
15594
15595 delete programMap[ programId ];
15596
15597 }
15598
15599 delete bindingStates[ geometryId ];
15600
15601 }
15602
15603 }
15604
15605 function releaseStatesOfGeometry( geometry ) {
15606
15607 if ( bindingStates[ geometry.id ] === undefined ) return;
15608
15609 const programMap = bindingStates[ geometry.id ];
15610
15611 for ( const programId in programMap ) {
15612
15613 const stateMap = programMap[ programId ];
15614
15615 for ( const wireframe in stateMap ) {
15616
15618
15619 delete stateMap[ wireframe ];
15620
15621 }
15622
15623 delete programMap[ programId ];
15624
15625 }
15626
15627 delete bindingStates[ geometry.id ];
15628
15629 }
15630
15631 function releaseStatesOfProgram( program ) {
15632
15633 for ( const geometryId in bindingStates ) {
15634
15636
15637 if ( programMap[ program.id ] === undefined ) continue;
15638
15639 const stateMap = programMap[ program.id ];
15640
15641 for ( const wireframe in stateMap ) {
15642
15644
15645 delete stateMap[ wireframe ];
15646
15647 }
15648
15649 delete programMap[ program.id ];
15650
15651 }
15652
15653 }
15654
15655 function reset() {
15656
15658 forceUpdate = true;
15659
15660 if ( currentState === defaultState ) return;
15661
15664
15665 }
15666
15667 // for backward-compatibility
15668
15669 function resetDefaultState() {
15670
15671 defaultState.geometry = null;
15672 defaultState.program = null;
15673 defaultState.wireframe = false;
15674
15675 }
15676
15677 return {
15678
15679 setup: setup,
15680 reset: reset,
15685
15689
15690 };
15691
15692 }
15693
15695
15696 const isWebGL2 = capabilities.isWebGL2;
15697
15698 let mode;
15699
15700 function setMode( value ) {
15701
15702 mode = value;
15703
15704 }
15705
15706 function render( start, count ) {
15707
15708 gl.drawArrays( mode, start, count );
15709
15710 info.update( count, mode, 1 );
15711
15712 }
15713
15714 function renderInstances( start, count, primcount ) {
15715
15716 if ( primcount === 0 ) return;
15717
15719
15720 if ( isWebGL2 ) {
15721
15722 extension = gl;
15723 methodName = 'drawArraysInstanced';
15724
15725 } else {
15726
15727 extension = extensions.get( 'ANGLE_instanced_arrays' );
15728 methodName = 'drawArraysInstancedANGLE';
15729
15730 if ( extension === null ) {
15731
15732 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
15733 return;
15734
15735 }
15736
15737 }
15738
15739 extension[ methodName ]( mode, start, count, primcount );
15740
15741 info.update( count, mode, primcount );
15742
15743 }
15744
15745 function renderMultiDraw( starts, counts, drawCount ) {
15746
15747 if ( drawCount === 0 ) return;
15748
15749 const extension = extensions.get( 'WEBGL_multi_draw' );
15750 if ( extension === null ) {
15751
15752 for ( let i = 0; i < drawCount; i ++ ) {
15753
15754 this.render( starts[ i ], counts[ i ] );
15755
15756 }
15757
15758 } else {
15759
15760 extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );
15761
15762 let elementCount = 0;
15763 for ( let i = 0; i < drawCount; i ++ ) {
15764
15765 elementCount += counts[ i ];
15766
15767 }
15768
15769 info.update( elementCount, mode, 1 );
15770
15771 }
15772
15773 }
15774
15775 //
15776
15777 this.setMode = setMode;
15778 this.render = render;
15781
15782 }
15783
15784 function WebGLCapabilities( gl, extensions, parameters ) {
15785
15787
15788 function getMaxAnisotropy() {
15789
15790 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
15791
15792 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
15793
15794 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
15795
15796 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
15797
15798 } else {
15799
15800 maxAnisotropy = 0;
15801
15802 }
15803
15804 return maxAnisotropy;
15805
15806 }
15807
15808 function getMaxPrecision( precision ) {
15809
15810 if ( precision === 'highp' ) {
15811
15812 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
15813 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
15814
15815 return 'highp';
15816
15817 }
15818
15819 precision = 'mediump';
15820
15821 }
15822
15823 if ( precision === 'mediump' ) {
15824
15825 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
15826 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
15827
15828 return 'mediump';
15829
15830 }
15831
15832 }
15833
15834 return 'lowp';
15835
15836 }
15837
15838 const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext';
15839
15840 let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
15842
15843 if ( maxPrecision !== precision ) {
15844
15845 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
15847
15848 }
15849
15850 const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' );
15851
15852 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
15853
15854 const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
15855 const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
15856 const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
15857 const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
15858
15859 const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
15860 const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
15861 const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
15862 const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
15863
15865 const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' );
15867
15868 const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0;
15869
15870 return {
15871
15873
15875
15878
15881
15886
15891
15895
15897
15898 };
15899
15900 }
15901
15902 function WebGLClipping( properties ) {
15903
15904 const scope = this;
15905
15906 let globalState = null,
15907 numGlobalPlanes = 0,
15908 localClippingEnabled = false,
15909 renderingShadows = false;
15910
15911 const plane = new Plane(),
15912 viewNormalMatrix = new Matrix3(),
15913
15914 uniform = { value: null, needsUpdate: false };
15915
15916 this.uniform = uniform;
15917 this.numPlanes = 0;
15918 this.numIntersection = 0;
15919
15920 this.init = function ( planes, enableLocalClipping ) {
15921
15922 const enabled =
15923 planes.length !== 0 ||
15925 // enable state of previous frame - the clipping code has to
15926 // run another frame in order to reset the state:
15927 numGlobalPlanes !== 0 ||
15929
15931
15932 numGlobalPlanes = planes.length;
15933
15934 return enabled;
15935
15936 };
15937
15938 this.beginShadows = function () {
15939
15940 renderingShadows = true;
15941 projectPlanes( null );
15942
15943 };
15944
15945 this.endShadows = function () {
15946
15947 renderingShadows = false;
15948
15949 };
15950
15951 this.setGlobalState = function ( planes, camera ) {
15952
15953 globalState = projectPlanes( planes, camera, 0 );
15954
15955 };
15956
15957 this.setState = function ( material, camera, useCache ) {
15958
15959 const planes = material.clippingPlanes,
15960 clipIntersection = material.clipIntersection,
15961 clipShadows = material.clipShadows;
15962
15963 const materialProperties = properties.get( material );
15964
15965 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
15966
15967 // there's no local clipping
15968
15969 if ( renderingShadows ) {
15970
15971 // there's no global clipping
15972
15973 projectPlanes( null );
15974
15975 } else {
15976
15978
15979 }
15980
15981 } else {
15982
15984 lGlobal = nGlobal * 4;
15985
15986 let dstArray = materialProperties.clippingState || null;
15987
15988 uniform.value = dstArray; // ensure unique state
15989
15991
15992 for ( let i = 0; i !== lGlobal; ++ i ) {
15993
15994 dstArray[ i ] = globalState[ i ];
15995
15996 }
15997
15998 materialProperties.clippingState = dstArray;
15999 this.numIntersection = clipIntersection ? this.numPlanes : 0;
16000 this.numPlanes += nGlobal;
16001
16002 }
16003
16004
16005 };
16006
16007 function resetGlobalState() {
16008
16009 if ( uniform.value !== globalState ) {
16010
16011 uniform.value = globalState;
16012 uniform.needsUpdate = numGlobalPlanes > 0;
16013
16014 }
16015
16016 scope.numPlanes = numGlobalPlanes;
16017 scope.numIntersection = 0;
16018
16019 }
16020
16022
16023 const nPlanes = planes !== null ? planes.length : 0;
16024 let dstArray = null;
16025
16026 if ( nPlanes !== 0 ) {
16027
16028 dstArray = uniform.value;
16029
16030 if ( skipTransform !== true || dstArray === null ) {
16031
16032 const flatSize = dstOffset + nPlanes * 4,
16033 viewMatrix = camera.matrixWorldInverse;
16034
16035 viewNormalMatrix.getNormalMatrix( viewMatrix );
16036
16037 if ( dstArray === null || dstArray.length < flatSize ) {
16038
16040
16041 }
16042
16043 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
16044
16045 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
16046
16047 plane.normal.toArray( dstArray, i4 );
16048 dstArray[ i4 + 3 ] = plane.constant;
16049
16050 }
16051
16052 }
16053
16054 uniform.value = dstArray;
16055 uniform.needsUpdate = true;
16056
16057 }
16058
16059 scope.numPlanes = nPlanes;
16060 scope.numIntersection = 0;
16061
16062 return dstArray;
16063
16064 }
16065
16066 }
16067
16068 function WebGLCubeMaps( renderer ) {
16069
16070 let cubemaps = new WeakMap();
16071
16072 function mapTextureMapping( texture, mapping ) {
16073
16075
16077
16078 } else if ( mapping === EquirectangularRefractionMapping ) {
16079
16081
16082 }
16083
16084 return texture;
16085
16086 }
16087
16088 function get( texture ) {
16089
16090 if ( texture && texture.isTexture ) {
16091
16092 const mapping = texture.mapping;
16093
16095
16096 if ( cubemaps.has( texture ) ) {
16097
16098 const cubemap = cubemaps.get( texture ).texture;
16099 return mapTextureMapping( cubemap, texture.mapping );
16100
16101 } else {
16102
16103 const image = texture.image;
16104
16105 if ( image && image.height > 0 ) {
16106
16107 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 );
16108 renderTarget.fromEquirectangularTexture( renderer, texture );
16110
16111 texture.addEventListener( 'dispose', onTextureDispose );
16112
16113 return mapTextureMapping( renderTarget.texture, texture.mapping );
16114
16115 } else {
16116
16117 // image not yet ready. try the conversion next frame
16118
16119 return null;
16120
16121 }
16122
16123 }
16124
16125 }
16126
16127 }
16128
16129 return texture;
16130
16131 }
16132
16133 function onTextureDispose( event ) {
16134
16135 const texture = event.target;
16136
16137 texture.removeEventListener( 'dispose', onTextureDispose );
16138
16139 const cubemap = cubemaps.get( texture );
16140
16141 if ( cubemap !== undefined ) {
16142
16143 cubemaps.delete( texture );
16144 cubemap.dispose();
16145
16146 }
16147
16148 }
16149
16150 function dispose() {
16151
16152 cubemaps = new WeakMap();
16153
16154 }
16155
16156 return {
16157 get: get,
16159 };
16160
16161 }
16162
16163 class OrthographicCamera extends Camera {
16164
16165 constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {
16166
16167 super();
16168
16169 this.isOrthographicCamera = true;
16170
16171 this.type = 'OrthographicCamera';
16172
16173 this.zoom = 1;
16174 this.view = null;
16175
16176 this.left = left;
16177 this.right = right;
16178 this.top = top;
16179 this.bottom = bottom;
16180
16181 this.near = near;
16182 this.far = far;
16183
16185
16186 }
16187
16188 copy( source, recursive ) {
16189
16190 super.copy( source, recursive );
16191
16192 this.left = source.left;
16193 this.right = source.right;
16194 this.top = source.top;
16195 this.bottom = source.bottom;
16196 this.near = source.near;
16197 this.far = source.far;
16198
16199 this.zoom = source.zoom;
16200 this.view = source.view === null ? null : Object.assign( {}, source.view );
16201
16202 return this;
16203
16204 }
16205
16207
16208 if ( this.view === null ) {
16209
16210 this.view = {
16211 enabled: true,
16212 fullWidth: 1,
16213 fullHeight: 1,
16214 offsetX: 0,
16215 offsetY: 0,
16216 width: 1,
16217 height: 1
16218 };
16219
16220 }
16221
16222 this.view.enabled = true;
16223 this.view.fullWidth = fullWidth;
16224 this.view.fullHeight = fullHeight;
16225 this.view.offsetX = x;
16226 this.view.offsetY = y;
16227 this.view.width = width;
16228 this.view.height = height;
16229
16231
16232 }
16233
16234 clearViewOffset() {
16235
16236 if ( this.view !== null ) {
16237
16238 this.view.enabled = false;
16239
16240 }
16241
16243
16244 }
16245
16247
16248 const dx = ( this.right - this.left ) / ( 2 * this.zoom );
16249 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
16250 const cx = ( this.right + this.left ) / 2;
16251 const cy = ( this.top + this.bottom ) / 2;
16252
16253 let left = cx - dx;
16254 let right = cx + dx;
16255 let top = cy + dy;
16256 let bottom = cy - dy;
16257
16258 if ( this.view !== null && this.view.enabled ) {
16259
16260 const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;
16261 const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;
16262
16263 left += scaleW * this.view.offsetX;
16264 right = left + scaleW * this.view.width;
16265 top -= scaleH * this.view.offsetY;
16266 bottom = top - scaleH * this.view.height;
16267
16268 }
16269
16270 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem );
16271
16272 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert();
16273
16274 }
16275
16276 toJSON( meta ) {
16277
16278 const data = super.toJSON( meta );
16279
16280 data.object.zoom = this.zoom;
16281 data.object.left = this.left;
16282 data.object.right = this.right;
16283 data.object.top = this.top;
16284 data.object.bottom = this.bottom;
16285 data.object.near = this.near;
16286 data.object.far = this.far;
16287
16288 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
16289
16290 return data;
16291
16292 }
16293
16294 }
16295
16296 const LOD_MIN = 4;
16297
16298 // The standard deviations (radians) associated with the extra mips. These are
16299 // chosen to approximate a Trowbridge-Reitz distribution function times the
16300 // geometric shadowing function. These sigma values squared must match the
16301 // variance #defines in cube_uv_reflection_fragment.glsl.js.
16302 const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
16303
16304 // The maximum length of the blur for loop. Smaller sigmas will use fewer
16305 // samples and exit early, but not recompile the shader.
16306 const MAX_SAMPLES = 20;
16307
16308 const _flatCamera = /*@__PURE__*/ new OrthographicCamera();
16309 const _clearColor = /*@__PURE__*/ new Color();
16310 let _oldTarget = null;
16313
16314 // Golden Ratio
16315 const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
16316 const INV_PHI = 1 / PHI;
16317
16318 // Vertices of a dodecahedron (except the opposites, which represent the
16319 // same axis), used as axis directions evenly spread on a sphere.
16320 const _axisDirections = [
16321 /*@__PURE__*/ new Vector3( 1, 1, 1 ),
16322 /*@__PURE__*/ new Vector3( - 1, 1, 1 ),
16323 /*@__PURE__*/ new Vector3( 1, 1, - 1 ),
16324 /*@__PURE__*/ new Vector3( - 1, 1, - 1 ),
16325 /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),
16326 /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),
16327 /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),
16328 /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),
16329 /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),
16330 /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ];
16331
16347 class PMREMGenerator {
16348
16349 constructor( renderer ) {
16350
16351 this._renderer = renderer;
16352 this._pingPongRenderTarget = null;
16353
16354 this._lodMax = 0;
16355 this._cubeSize = 0;
16356 this._lodPlanes = [];
16357 this._sizeLods = [];
16358 this._sigmas = [];
16359
16360 this._blurMaterial = null;
16361 this._cubemapMaterial = null;
16362 this._equirectMaterial = null;
16363
16364 this._compileMaterial( this._blurMaterial );
16365
16366 }
16367
16375 fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
16376
16377 _oldTarget = this._renderer.getRenderTarget();
16378 _oldActiveCubeFace = this._renderer.getActiveCubeFace();
16379 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16380
16381 this._setSize( 256 );
16382
16383 const cubeUVRenderTarget = this._allocateTargets();
16384 cubeUVRenderTarget.depthBuffer = true;
16385
16386 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );
16387
16388 if ( sigma > 0 ) {
16389
16390 this._blur( cubeUVRenderTarget, 0, 0, sigma );
16391
16392 }
16393
16396
16397 return cubeUVRenderTarget;
16398
16399 }
16400
16407
16409
16410 }
16411
16417 fromCubemap( cubemap, renderTarget = null ) {
16418
16419 return this._fromTexture( cubemap, renderTarget );
16420
16421 }
16422
16428
16429 if ( this._cubemapMaterial === null ) {
16430
16433
16434 }
16435
16436 }
16437
16443
16444 if ( this._equirectMaterial === null ) {
16445
16448
16449 }
16450
16451 }
16452
16458 dispose() {
16459
16460 this._dispose();
16461
16462 if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
16463 if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();
16464
16465 }
16466
16467 // private interface
16468
16469 _setSize( cubeSize ) {
16470
16471 this._lodMax = Math.floor( Math.log2( cubeSize ) );
16472 this._cubeSize = Math.pow( 2, this._lodMax );
16473
16474 }
16475
16476 _dispose() {
16477
16478 if ( this._blurMaterial !== null ) this._blurMaterial.dispose();
16479
16480 if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();
16481
16482 for ( let i = 0; i < this._lodPlanes.length; i ++ ) {
16483
16484 this._lodPlanes[ i ].dispose();
16485
16486 }
16487
16488 }
16489
16491
16492 this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
16493 outputTarget.scissorTest = false;
16494 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
16495
16496 }
16497
16499
16500 if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {
16501
16502 this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );
16503
16504 } else { // Equirectangular
16505
16506 this._setSize( texture.image.width / 4 );
16507
16508 }
16509
16510 _oldTarget = this._renderer.getRenderTarget();
16511 _oldActiveCubeFace = this._renderer.getActiveCubeFace();
16512 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
16513
16518
16519 return cubeUVRenderTarget;
16520
16521 }
16522
16524
16525 const width = 3 * Math.max( this._cubeSize, 16 * 7 );
16526 const height = 4 * this._cubeSize;
16527
16528 const params = {
16531 generateMipmaps: false,
16532 type: HalfFloatType,
16533 format: RGBAFormat,
16535 depthBuffer: false
16536 };
16537
16539
16540 if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {
16541
16542 if ( this._pingPongRenderTarget !== null ) {
16543
16544 this._dispose();
16545
16546 }
16547
16549
16550 const { _lodMax } = this;
16551 ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );
16552
16553 this._blurMaterial = _getBlurShader( _lodMax, width, height );
16554
16555 }
16556
16557 return cubeUVRenderTarget;
16558
16559 }
16560
16562
16563 const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
16564 this._renderer.compile( tmpMesh, _flatCamera );
16565
16566 }
16567
16569
16570 const fov = 90;
16571 const aspect = 1;
16572 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
16573 const upSign = [ 1, - 1, 1, 1, 1, 1 ];
16574 const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];
16575 const renderer = this._renderer;
16576
16577 const originalAutoClear = renderer.autoClear;
16578 const toneMapping = renderer.toneMapping;
16579 renderer.getClearColor( _clearColor );
16580
16581 renderer.toneMapping = NoToneMapping;
16582 renderer.autoClear = false;
16583
16585 name: 'PMREM.Background',
16586 side: BackSide,
16587 depthWrite: false,
16588 depthTest: false,
16589 } );
16590
16591 const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );
16592
16593 let useSolidColor = false;
16594 const background = scene.background;
16595
16596 if ( background ) {
16597
16598 if ( background.isColor ) {
16599
16600 backgroundMaterial.color.copy( background );
16601 scene.background = null;
16602 useSolidColor = true;
16603
16604 }
16605
16606 } else {
16607
16608 backgroundMaterial.color.copy( _clearColor );
16609 useSolidColor = true;
16610
16611 }
16612
16613 for ( let i = 0; i < 6; i ++ ) {
16614
16615 const col = i % 3;
16616
16617 if ( col === 0 ) {
16618
16619 cubeCamera.up.set( 0, upSign[ i ], 0 );
16620 cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
16621
16622 } else if ( col === 1 ) {
16623
16624 cubeCamera.up.set( 0, 0, upSign[ i ] );
16625 cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
16626
16627 } else {
16628
16629 cubeCamera.up.set( 0, upSign[ i ], 0 );
16630 cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
16631
16632 }
16633
16634 const size = this._cubeSize;
16635
16636 _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );
16637
16638 renderer.setRenderTarget( cubeUVRenderTarget );
16639
16640 if ( useSolidColor ) {
16641
16642 renderer.render( backgroundBox, cubeCamera );
16643
16644 }
16645
16646 renderer.render( scene, cubeCamera );
16647
16648 }
16649
16650 backgroundBox.geometry.dispose();
16651 backgroundBox.material.dispose();
16652
16653 renderer.toneMapping = toneMapping;
16654 renderer.autoClear = originalAutoClear;
16655 scene.background = background;
16656
16657 }
16658
16660
16661 const renderer = this._renderer;
16662
16663 const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );
16664
16665 if ( isCubeTexture ) {
16666
16667 if ( this._cubemapMaterial === null ) {
16668
16670
16671 }
16672
16673 this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;
16674
16675 } else {
16676
16677 if ( this._equirectMaterial === null ) {
16678
16680
16681 }
16682
16683 }
16684
16686 const mesh = new Mesh( this._lodPlanes[ 0 ], material );
16687
16688 const uniforms = material.uniforms;
16689
16690 uniforms[ 'envMap' ].value = texture;
16691
16692 const size = this._cubeSize;
16693
16694 _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );
16695
16696 renderer.setRenderTarget( cubeUVRenderTarget );
16697 renderer.render( mesh, _flatCamera );
16698
16699 }
16700
16702
16703 const renderer = this._renderer;
16704 const autoClear = renderer.autoClear;
16705 renderer.autoClear = false;
16706
16707 for ( let i = 1; i < this._lodPlanes.length; i ++ ) {
16708
16709 const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );
16710
16711 const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ];
16712
16713 this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );
16714
16715 }
16716
16717 renderer.autoClear = autoClear;
16718
16719 }
16720
16729
16731
16732 this._halfBlur(
16735 lodIn,
16736 lodOut,
16737 sigma,
16738 'latitudinal',
16739 poleAxis );
16740
16741 this._halfBlur(
16744 lodOut,
16745 lodOut,
16746 sigma,
16747 'longitudinal',
16748 poleAxis );
16749
16750 }
16751
16753
16754 const renderer = this._renderer;
16755 const blurMaterial = this._blurMaterial;
16756
16757 if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {
16758
16759 console.error(
16760 'blur direction must be either latitudinal or longitudinal!' );
16761
16762 }
16763
16764 // Number of standard deviations at which to cut off the discrete approximation.
16765 const STANDARD_DEVIATIONS = 3;
16766
16767 const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
16768 const blurUniforms = blurMaterial.uniforms;
16769
16770 const pixels = this._sizeLods[ lodIn ] - 1;
16771 const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
16774
16775 if ( samples > MAX_SAMPLES ) {
16776
16777 console.warn( `sigmaRadians, ${
16780
16781 }
16782
16783 const weights = [];
16784 let sum = 0;
16785
16786 for ( let i = 0; i < MAX_SAMPLES; ++ i ) {
16787
16788 const x = i / sigmaPixels;
16789 const weight = Math.exp( - x * x / 2 );
16790 weights.push( weight );
16791
16792 if ( i === 0 ) {
16793
16794 sum += weight;
16795
16796 } else if ( i < samples ) {
16797
16798 sum += 2 * weight;
16799
16800 }
16801
16802 }
16803
16804 for ( let i = 0; i < weights.length; i ++ ) {
16805
16806 weights[ i ] = weights[ i ] / sum;
16807
16808 }
16809
16810 blurUniforms[ 'envMap' ].value = targetIn.texture;
16811 blurUniforms[ 'samples' ].value = samples;
16812 blurUniforms[ 'weights' ].value = weights;
16813 blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';
16814
16815 if ( poleAxis ) {
16816
16817 blurUniforms[ 'poleAxis' ].value = poleAxis;
16818
16819 }
16820
16821 const { _lodMax } = this;
16822 blurUniforms[ 'dTheta' ].value = radiansPerPixel;
16823 blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;
16824
16825 const outputSize = this._sizeLods[ lodOut ];
16826 const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
16827 const y = 4 * ( this._cubeSize - outputSize );
16828
16829 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
16830 renderer.setRenderTarget( targetOut );
16831 renderer.render( blurMesh, _flatCamera );
16832
16833 }
16834
16835 }
16836
16837
16838
16839 function _createPlanes( lodMax ) {
16840
16841 const lodPlanes = [];
16842 const sizeLods = [];
16843 const sigmas = [];
16844
16845 let lod = lodMax;
16846
16847 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;
16848
16849 for ( let i = 0; i < totalLods; i ++ ) {
16850
16851 const sizeLod = Math.pow( 2, lod );
16852 sizeLods.push( sizeLod );
16853 let sigma = 1.0 / sizeLod;
16854
16855 if ( i > lodMax - LOD_MIN ) {
16856
16857 sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];
16858
16859 } else if ( i === 0 ) {
16860
16861 sigma = 0;
16862
16863 }
16864
16865 sigmas.push( sigma );
16866
16867 const texelSize = 1.0 / ( sizeLod - 2 );
16868 const min = - texelSize;
16869 const max = 1 + texelSize;
16870 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];
16871
16872 const cubeFaces = 6;
16873 const vertices = 6;
16874 const positionSize = 3;
16875 const uvSize = 2;
16876 const faceIndexSize = 1;
16877
16879 const uv = new Float32Array( uvSize * vertices * cubeFaces );
16881
16882 for ( let face = 0; face < cubeFaces; face ++ ) {
16883
16884 const x = ( face % 3 ) * 2 / 3 - 1;
16885 const y = face > 2 ? 0 : - 1;
16886 const coordinates = [
16887 x, y, 0,
16888 x + 2 / 3, y, 0,
16889 x + 2 / 3, y + 1, 0,
16890 x, y, 0,
16891 x + 2 / 3, y + 1, 0,
16892 x, y + 1, 0
16893 ];
16895 uv.set( uv1, uvSize * vertices * face );
16896 const fill = [ face, face, face, face, face, face ];
16898
16899 }
16900
16901 const planes = new BufferGeometry();
16902 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
16903 planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
16904 planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
16905 lodPlanes.push( planes );
16906
16907 if ( lod > LOD_MIN ) {
16908
16909 lod --;
16910
16911 }
16912
16913 }
16914
16915 return { lodPlanes, sizeLods, sigmas };
16916
16917 }
16918
16919 function _createRenderTarget( width, height, params ) {
16920
16923 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
16924 cubeUVRenderTarget.scissorTest = true;
16925 return cubeUVRenderTarget;
16926
16927 }
16928
16929 function _setViewport( target, x, y, width, height ) {
16930
16931 target.viewport.set( x, y, width, height );
16932 target.scissor.set( x, y, width, height );
16933
16934 }
16935
16936 function _getBlurShader( lodMax, width, height ) {
16937
16938 const weights = new Float32Array( MAX_SAMPLES );
16939 const poleAxis = new Vector3( 0, 1, 0 );
16940 const shaderMaterial = new ShaderMaterial( {
16941
16942 name: 'SphericalGaussianBlur',
16943
16944 defines: {
16945 'n': MAX_SAMPLES,
16946 'CUBEUV_TEXEL_WIDTH': 1.0 / width,
16947 'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
16948 'CUBEUV_MAX_MIP': `${lodMax}.0`,
16949 },
16950
16951 uniforms: {
16952 'envMap': { value: null },
16953 'samples': { value: 1 },
16954 'weights': { value: weights },
16955 'latitudinal': { value: false },
16956 'dTheta': { value: 0 },
16957 'mipInt': { value: 0 },
16958 'poleAxis': { value: poleAxis }
16959 },
16960
16962
16963 fragmentShader: /* glsl */`
16964
16967
16969
16971 uniform int samples;
16972 uniform float weights[ n ];
16973 uniform bool latitudinal;
16974 uniform float dTheta;
16975 uniform float mipInt;
16977
16978 #define ENVMAP_TYPE_CUBE_UV
16979 #include <cube_uv_reflection_fragment>
16980
16981 vec3 getSample( float theta, vec3 axis ) {
16982
16983 float cosTheta = cos( theta );
16984 // Rodrigues' axis-angle rotation
16987 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );
16988
16990
16991 }
16992
16993 void main() {
16994
16996
16997 if ( all( equal( axis, vec3( 0.0 ) ) ) ) {
16998
16999 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );
17000
17001 }
17002
17003 axis = normalize( axis );
17004
17005 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
17006 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );
17007
17008 for ( int i = 1; i < n; i++ ) {
17009
17010 if ( i >= samples ) {
17011
17012 break;
17013
17014 }
17015
17016 float theta = dTheta * float( i );
17017 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
17018 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );
17019
17020 }
17021
17022 }
17023 `,
17024
17026 depthTest: false,
17027 depthWrite: false
17028
17029 } );
17030
17031 return shaderMaterial;
17032
17033 }
17034
17035 function _getEquirectMaterial() {
17036
17037 return new ShaderMaterial( {
17038
17039 name: 'EquirectangularToCubeUV',
17040
17041 uniforms: {
17042 'envMap': { value: null }
17043 },
17044
17046
17047 fragmentShader: /* glsl */`
17048
17051
17053
17055
17056 #include <common>
17057
17058 void main() {
17059
17062
17063 gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );
17064
17065 }
17066 `,
17067
17069 depthTest: false,
17070 depthWrite: false
17071
17072 } );
17073
17074 }
17075
17076 function _getCubemapMaterial() {
17077
17078 return new ShaderMaterial( {
17079
17080 name: 'CubemapToCubeUV',
17081
17082 uniforms: {
17083 'envMap': { value: null },
17084 'flipEnvMap': { value: - 1 }
17085 },
17086
17088
17089 fragmentShader: /* glsl */`
17090
17093
17094 uniform float flipEnvMap;
17095
17097
17099
17100 void main() {
17101
17103
17104 }
17105 `,
17106
17108 depthTest: false,
17109 depthWrite: false
17110
17111 } );
17112
17113 }
17114
17115 function _getCommonVertexShader() {
17116
17117 return /* glsl */`
17118
17121
17122 attribute float faceIndex;
17123
17125
17126 // RH coordinate system; PMREM face-indexing convention
17127 vec3 getDirection( vec2 uv, float face ) {
17128
17129 uv = 2.0 * uv - 1.0;
17130
17131 vec3 direction = vec3( uv, 1.0 );
17132
17133 if ( face == 0.0 ) {
17134
17135 direction = direction.zyx; // ( 1, v, u ) pos x
17136
17137 } else if ( face == 1.0 ) {
17138
17139 direction = direction.xzy;
17140 direction.xz *= -1.0; // ( -u, 1, -v ) pos y
17141
17142 } else if ( face == 2.0 ) {
17143
17144 direction.x *= -1.0; // ( -u, v, 1 ) pos z
17145
17146 } else if ( face == 3.0 ) {
17147
17148 direction = direction.zyx;
17149 direction.xz *= -1.0; // ( -1, v, -u ) neg x
17150
17151 } else if ( face == 4.0 ) {
17152
17153 direction = direction.xzy;
17154 direction.xy *= -1.0; // ( -u, -1, v ) neg y
17155
17156 } else if ( face == 5.0 ) {
17157
17158 direction.z *= -1.0; // ( u, v, -1 ) neg z
17159
17160 }
17161
17162 return direction;
17163
17164 }
17165
17166 void main() {
17167
17169 gl_Position = vec4( position, 1.0 );
17170
17171 }
17172 `;
17173
17174 }
17175
17176 function WebGLCubeUVMaps( renderer ) {
17177
17178 let cubeUVmaps = new WeakMap();
17179
17180 let pmremGenerator = null;
17181
17182 function get( texture ) {
17183
17184 if ( texture && texture.isTexture ) {
17185
17186 const mapping = texture.mapping;
17187
17190
17191 // equirect/cube map to cubeUV conversion
17192
17193 if ( isEquirectMap || isCubeMap ) {
17194
17195 if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) {
17196
17197 texture.needsPMREMUpdate = false;
17198
17200
17201 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17202
17205
17206 return renderTarget.texture;
17207
17208 } else {
17209
17210 if ( cubeUVmaps.has( texture ) ) {
17211
17212 return cubeUVmaps.get( texture ).texture;
17213
17214 } else {
17215
17216 const image = texture.image;
17217
17218 if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {
17219
17220 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );
17221
17222 const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
17224
17225 texture.addEventListener( 'dispose', onTextureDispose );
17226
17227 return renderTarget.texture;
17228
17229 } else {
17230
17231 // image not yet ready. try the conversion next frame
17232
17233 return null;
17234
17235 }
17236
17237 }
17238
17239 }
17240
17241 }
17242
17243 }
17244
17245 return texture;
17246
17247 }
17248
17249 function isCubeTextureComplete( image ) {
17250
17251 let count = 0;
17252 const length = 6;
17253
17254 for ( let i = 0; i < length; i ++ ) {
17255
17256 if ( image[ i ] !== undefined ) count ++;
17257
17258 }
17259
17260 return count === length;
17261
17262
17263 }
17264
17265 function onTextureDispose( event ) {
17266
17267 const texture = event.target;
17268
17269 texture.removeEventListener( 'dispose', onTextureDispose );
17270
17271 const cubemapUV = cubeUVmaps.get( texture );
17272
17273 if ( cubemapUV !== undefined ) {
17274
17275 cubeUVmaps.delete( texture );
17276 cubemapUV.dispose();
17277
17278 }
17279
17280 }
17281
17282 function dispose() {
17283
17284 cubeUVmaps = new WeakMap();
17285
17286 if ( pmremGenerator !== null ) {
17287
17288 pmremGenerator.dispose();
17289 pmremGenerator = null;
17290
17291 }
17292
17293 }
17294
17295 return {
17296 get: get,
17298 };
17299
17300 }
17301
17302 function WebGLExtensions( gl ) {
17303
17304 const extensions = {};
17305
17306 function getExtension( name ) {
17307
17308 if ( extensions[ name ] !== undefined ) {
17309
17310 return extensions[ name ];
17311
17312 }
17313
17314 let extension;
17315
17316 switch ( name ) {
17317
17318 case 'WEBGL_depth_texture':
17319 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
17320 break;
17321
17322 case 'EXT_texture_filter_anisotropic':
17323 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
17324 break;
17325
17326 case 'WEBGL_compressed_texture_s3tc':
17327 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
17328 break;
17329
17330 case 'WEBGL_compressed_texture_pvrtc':
17331 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
17332 break;
17333
17334 default:
17335 extension = gl.getExtension( name );
17336
17337 }
17338
17340
17341 return extension;
17342
17343 }
17344
17345 return {
17346
17347 has: function ( name ) {
17348
17349 return getExtension( name ) !== null;
17350
17351 },
17352
17353 init: function ( capabilities ) {
17354
17355 if ( capabilities.isWebGL2 ) {
17356
17357 getExtension( 'EXT_color_buffer_float' );
17358 getExtension( 'WEBGL_clip_cull_distance' );
17359
17360 } else {
17361
17362 getExtension( 'WEBGL_depth_texture' );
17363 getExtension( 'OES_texture_float' );
17364 getExtension( 'OES_texture_half_float' );
17365 getExtension( 'OES_texture_half_float_linear' );
17366 getExtension( 'OES_standard_derivatives' );
17367 getExtension( 'OES_element_index_uint' );
17368 getExtension( 'OES_vertex_array_object' );
17369 getExtension( 'ANGLE_instanced_arrays' );
17370
17371 }
17372
17373 getExtension( 'OES_texture_float_linear' );
17374 getExtension( 'EXT_color_buffer_half_float' );
17375 getExtension( 'WEBGL_multisampled_render_to_texture' );
17376
17377 },
17378
17379 get: function ( name ) {
17380
17381 const extension = getExtension( name );
17382
17383 if ( extension === null ) {
17384
17385 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
17386
17387 }
17388
17389 return extension;
17390
17391 }
17392
17393 };
17394
17395 }
17396
17398
17399 const geometries = {};
17400 const wireframeAttributes = new WeakMap();
17401
17402 function onGeometryDispose( event ) {
17403
17404 const geometry = event.target;
17405
17406 if ( geometry.index !== null ) {
17407
17408 attributes.remove( geometry.index );
17409
17410 }
17411
17412 for ( const name in geometry.attributes ) {
17413
17414 attributes.remove( geometry.attributes[ name ] );
17415
17416 }
17417
17418 for ( const name in geometry.morphAttributes ) {
17419
17420 const array = geometry.morphAttributes[ name ];
17421
17422 for ( let i = 0, l = array.length; i < l; i ++ ) {
17423
17424 attributes.remove( array[ i ] );
17425
17426 }
17427
17428 }
17429
17430 geometry.removeEventListener( 'dispose', onGeometryDispose );
17431
17432 delete geometries[ geometry.id ];
17433
17434 const attribute = wireframeAttributes.get( geometry );
17435
17436 if ( attribute ) {
17437
17438 attributes.remove( attribute );
17439 wireframeAttributes.delete( geometry );
17440
17441 }
17442
17443 bindingStates.releaseStatesOfGeometry( geometry );
17444
17445 if ( geometry.isInstancedBufferGeometry === true ) {
17446
17447 delete geometry._maxInstanceCount;
17448
17449 }
17450
17451 //
17452
17453 info.memory.geometries --;
17454
17455 }
17456
17457 function get( object, geometry ) {
17458
17459 if ( geometries[ geometry.id ] === true ) return geometry;
17460
17461 geometry.addEventListener( 'dispose', onGeometryDispose );
17462
17463 geometries[ geometry.id ] = true;
17464
17465 info.memory.geometries ++;
17466
17467 return geometry;
17468
17469 }
17470
17471 function update( geometry ) {
17472
17473 const geometryAttributes = geometry.attributes;
17474
17475 // Updating index buffer in VAO now. See WebGLBindingStates.
17476
17477 for ( const name in geometryAttributes ) {
17478
17479 attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
17480
17481 }
17482
17483 // morph targets
17484
17485 const morphAttributes = geometry.morphAttributes;
17486
17487 for ( const name in morphAttributes ) {
17488
17489 const array = morphAttributes[ name ];
17490
17491 for ( let i = 0, l = array.length; i < l; i ++ ) {
17492
17493 attributes.update( array[ i ], gl.ARRAY_BUFFER );
17494
17495 }
17496
17497 }
17498
17499 }
17500
17502
17503 const indices = [];
17504
17505 const geometryIndex = geometry.index;
17506 const geometryPosition = geometry.attributes.position;
17507 let version = 0;
17508
17509 if ( geometryIndex !== null ) {
17510
17511 const array = geometryIndex.array;
17512 version = geometryIndex.version;
17513
17514 for ( let i = 0, l = array.length; i < l; i += 3 ) {
17515
17516 const a = array[ i + 0 ];
17517 const b = array[ i + 1 ];
17518 const c = array[ i + 2 ];
17519
17520 indices.push( a, b, b, c, c, a );
17521
17522 }
17523
17524 } else if ( geometryPosition !== undefined ) {
17525
17526 const array = geometryPosition.array;
17527 version = geometryPosition.version;
17528
17529 for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
17530
17531 const a = i + 0;
17532 const b = i + 1;
17533 const c = i + 2;
17534
17535 indices.push( a, b, b, c, c, a );
17536
17537 }
17538
17539 } else {
17540
17541 return;
17542
17543 }
17544
17546 attribute.version = version;
17547
17548 // Updating index buffer in VAO now. See WebGLBindingStates
17549
17550 //
17551
17553
17555
17556 //
17557
17559
17560 }
17561
17562 function getWireframeAttribute( geometry ) {
17563
17565
17566 if ( currentAttribute ) {
17567
17568 const geometryIndex = geometry.index;
17569
17570 if ( geometryIndex !== null ) {
17571
17572 // if the attribute is obsolete, create a new one
17573
17574 if ( currentAttribute.version < geometryIndex.version ) {
17575
17577
17578 }
17579
17580 }
17581
17582 } else {
17583
17585
17586 }
17587
17588 return wireframeAttributes.get( geometry );
17589
17590 }
17591
17592 return {
17593
17594 get: get,
17595 update: update,
17596
17598
17599 };
17600
17601 }
17602
17604
17605 const isWebGL2 = capabilities.isWebGL2;
17606
17607 let mode;
17608
17609 function setMode( value ) {
17610
17611 mode = value;
17612
17613 }
17614
17615 let type, bytesPerElement;
17616
17617 function setIndex( value ) {
17618
17619 type = value.type;
17620 bytesPerElement = value.bytesPerElement;
17621
17622 }
17623
17624 function render( start, count ) {
17625
17626 gl.drawElements( mode, count, type, start * bytesPerElement );
17627
17628 info.update( count, mode, 1 );
17629
17630 }
17631
17632 function renderInstances( start, count, primcount ) {
17633
17634 if ( primcount === 0 ) return;
17635
17637
17638 if ( isWebGL2 ) {
17639
17640 extension = gl;
17641 methodName = 'drawElementsInstanced';
17642
17643 } else {
17644
17645 extension = extensions.get( 'ANGLE_instanced_arrays' );
17646 methodName = 'drawElementsInstancedANGLE';
17647
17648 if ( extension === null ) {
17649
17650 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
17651 return;
17652
17653 }
17654
17655 }
17656
17657 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount );
17658
17659 info.update( count, mode, primcount );
17660
17661 }
17662
17663 function renderMultiDraw( starts, counts, drawCount ) {
17664
17665 if ( drawCount === 0 ) return;
17666
17667 const extension = extensions.get( 'WEBGL_multi_draw' );
17668 if ( extension === null ) {
17669
17670 for ( let i = 0; i < drawCount; i ++ ) {
17671
17672 this.render( starts[ i ] / bytesPerElement, counts[ i ] );
17673
17674 }
17675
17676 } else {
17677
17678 extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );
17679
17680 let elementCount = 0;
17681 for ( let i = 0; i < drawCount; i ++ ) {
17682
17683 elementCount += counts[ i ];
17684
17685 }
17686
17687 info.update( elementCount, mode, 1 );
17688
17689 }
17690
17691 }
17692
17693 //
17694
17695 this.setMode = setMode;
17696 this.setIndex = setIndex;
17697 this.render = render;
17700
17701 }
17702
17703 function WebGLInfo( gl ) {
17704
17705 const memory = {
17706 geometries: 0,
17707 textures: 0
17708 };
17709
17710 const render = {
17711 frame: 0,
17712 calls: 0,
17713 triangles: 0,
17714 points: 0,
17715 lines: 0
17716 };
17717
17718 function update( count, mode, instanceCount ) {
17719
17720 render.calls ++;
17721
17722 switch ( mode ) {
17723
17724 case gl.TRIANGLES:
17725 render.triangles += instanceCount * ( count / 3 );
17726 break;
17727
17728 case gl.LINES:
17729 render.lines += instanceCount * ( count / 2 );
17730 break;
17731
17732 case gl.LINE_STRIP:
17733 render.lines += instanceCount * ( count - 1 );
17734 break;
17735
17736 case gl.LINE_LOOP:
17737 render.lines += instanceCount * count;
17738 break;
17739
17740 case gl.POINTS:
17741 render.points += instanceCount * count;
17742 break;
17743
17744 default:
17745 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
17746 break;
17747
17748 }
17749
17750 }
17751
17752 function reset() {
17753
17754 render.calls = 0;
17755 render.triangles = 0;
17756 render.points = 0;
17757 render.lines = 0;
17758
17759 }
17760
17761 return {
17762 memory: memory,
17763 render: render,
17764 programs: null,
17765 autoReset: true,
17766 reset: reset,
17767 update: update
17768 };
17769
17770 }
17771
17772 function numericalSort( a, b ) {
17773
17774 return a[ 0 ] - b[ 0 ];
17775
17776 }
17777
17778 function absNumericalSort( a, b ) {
17779
17780 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
17781
17782 }
17783
17785
17786 const influencesList = {};
17787 const morphInfluences = new Float32Array( 8 );
17788 const morphTextures = new WeakMap();
17789 const morph = new Vector4();
17790
17791 const workInfluences = [];
17792
17793 for ( let i = 0; i < 8; i ++ ) {
17794
17795 workInfluences[ i ] = [ i, 0 ];
17796
17797 }
17798
17799 function update( object, geometry, program ) {
17800
17801 const objectInfluences = object.morphTargetInfluences;
17802
17803 if ( capabilities.isWebGL2 === true ) {
17804
17805 // instead of using attributes, the WebGL 2 code path encodes morph targets
17806 // into an array of data textures. Each layer represents a single morph target.
17807
17808 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
17809 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
17810
17812
17813 if ( entry === undefined || entry.count !== morphTargetsCount ) {
17814
17815 if ( entry !== undefined ) entry.texture.dispose();
17816
17817 const hasMorphPosition = geometry.morphAttributes.position !== undefined;
17818 const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
17819 const hasMorphColors = geometry.morphAttributes.color !== undefined;
17820
17821 const morphTargets = geometry.morphAttributes.position || [];
17822 const morphNormals = geometry.morphAttributes.normal || [];
17823 const morphColors = geometry.morphAttributes.color || [];
17824
17825 let vertexDataCount = 0;
17826
17827 if ( hasMorphPosition === true ) vertexDataCount = 1;
17828 if ( hasMorphNormals === true ) vertexDataCount = 2;
17829 if ( hasMorphColors === true ) vertexDataCount = 3;
17830
17831 let width = geometry.attributes.position.count * vertexDataCount;
17832 let height = 1;
17833
17834 if ( width > capabilities.maxTextureSize ) {
17835
17836 height = Math.ceil( width / capabilities.maxTextureSize );
17837 width = capabilities.maxTextureSize;
17838
17839 }
17840
17841 const buffer = new Float32Array( width * height * 4 * morphTargetsCount );
17842
17844 texture.type = FloatType;
17845 texture.needsUpdate = true;
17846
17847 // fill buffer
17848
17850
17851 for ( let i = 0; i < morphTargetsCount; i ++ ) {
17852
17853 const morphTarget = morphTargets[ i ];
17854 const morphNormal = morphNormals[ i ];
17855 const morphColor = morphColors[ i ];
17856
17857 const offset = width * height * 4 * i;
17858
17859 for ( let j = 0; j < morphTarget.count; j ++ ) {
17860
17861 const stride = j * vertexDataStride;
17862
17863 if ( hasMorphPosition === true ) {
17864
17865 morph.fromBufferAttribute( morphTarget, j );
17866
17867 buffer[ offset + stride + 0 ] = morph.x;
17868 buffer[ offset + stride + 1 ] = morph.y;
17869 buffer[ offset + stride + 2 ] = morph.z;
17870 buffer[ offset + stride + 3 ] = 0;
17871
17872 }
17873
17874 if ( hasMorphNormals === true ) {
17875
17876 morph.fromBufferAttribute( morphNormal, j );
17877
17878 buffer[ offset + stride + 4 ] = morph.x;
17879 buffer[ offset + stride + 5 ] = morph.y;
17880 buffer[ offset + stride + 6 ] = morph.z;
17881 buffer[ offset + stride + 7 ] = 0;
17882
17883 }
17884
17885 if ( hasMorphColors === true ) {
17886
17887 morph.fromBufferAttribute( morphColor, j );
17888
17889 buffer[ offset + stride + 8 ] = morph.x;
17890 buffer[ offset + stride + 9 ] = morph.y;
17891 buffer[ offset + stride + 10 ] = morph.z;
17892 buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;
17893
17894 }
17895
17896 }
17897
17898 }
17899
17900 entry = {
17903 size: new Vector2( width, height )
17904 };
17905
17907
17908 function disposeTexture() {
17909
17910 texture.dispose();
17911
17912 morphTextures.delete( geometry );
17913
17914 geometry.removeEventListener( 'dispose', disposeTexture );
17915
17916 }
17917
17918 geometry.addEventListener( 'dispose', disposeTexture );
17919
17920 }
17921
17922 //
17923
17925
17926 for ( let i = 0; i < objectInfluences.length; i ++ ) {
17927
17929
17930 }
17931
17932 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
17933
17934 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
17935 program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );
17936
17937 program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
17938 program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );
17939
17940
17941 } else {
17942
17943 // When object doesn't have morph target influences defined, we treat it as a 0-length array
17944 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences
17945
17946 const length = objectInfluences === undefined ? 0 : objectInfluences.length;
17947
17949
17950 if ( influences === undefined || influences.length !== length ) {
17951
17952 // initialise list
17953
17954 influences = [];
17955
17956 for ( let i = 0; i < length; i ++ ) {
17957
17958 influences[ i ] = [ i, 0 ];
17959
17960 }
17961
17963
17964 }
17965
17966 // Collect influences
17967
17968 for ( let i = 0; i < length; i ++ ) {
17969
17970 const influence = influences[ i ];
17971
17972 influence[ 0 ] = i;
17973 influence[ 1 ] = objectInfluences[ i ];
17974
17975 }
17976
17978
17979 for ( let i = 0; i < 8; i ++ ) {
17980
17981 if ( i < length && influences[ i ][ 1 ] ) {
17982
17983 workInfluences[ i ][ 0 ] = influences[ i ][ 0 ];
17984 workInfluences[ i ][ 1 ] = influences[ i ][ 1 ];
17985
17986 } else {
17987
17988 workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER;
17989 workInfluences[ i ][ 1 ] = 0;
17990
17991 }
17992
17993 }
17994
17996
17997 const morphTargets = geometry.morphAttributes.position;
17998 const morphNormals = geometry.morphAttributes.normal;
17999
18001
18002 for ( let i = 0; i < 8; i ++ ) {
18003
18004 const influence = workInfluences[ i ];
18005 const index = influence[ 0 ];
18006 const value = influence[ 1 ];
18007
18008 if ( index !== Number.MAX_SAFE_INTEGER && value ) {
18009
18010 if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) {
18011
18012 geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] );
18013
18014 }
18015
18016 if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) {
18017
18018 geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] );
18019
18020 }
18021
18022 morphInfluences[ i ] = value;
18024
18025 } else {
18026
18027 if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) {
18028
18029 geometry.deleteAttribute( 'morphTarget' + i );
18030
18031 }
18032
18033 if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) {
18034
18035 geometry.deleteAttribute( 'morphNormal' + i );
18036
18037 }
18038
18039 morphInfluences[ i ] = 0;
18040
18041 }
18042
18043 }
18044
18045 // GLSL shader uses formula baseinfluence * base + sum(target * influence)
18046 // This allows us to switch between absolute morphs and relative morphs without changing shader code
18047 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence)
18048 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;
18049
18050 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
18051 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
18052
18053 }
18054
18055 }
18056
18057 return {
18058
18059 update: update
18060
18061 };
18062
18063 }
18064
18065 function WebGLObjects( gl, geometries, attributes, info ) {
18066
18067 let updateMap = new WeakMap();
18068
18069 function update( object ) {
18070
18071 const frame = info.render.frame;
18072
18073 const geometry = object.geometry;
18074 const buffergeometry = geometries.get( object, geometry );
18075
18076 // Update once per frame
18077
18078 if ( updateMap.get( buffergeometry ) !== frame ) {
18079
18080 geometries.update( buffergeometry );
18081
18083
18084 }
18085
18086 if ( object.isInstancedMesh ) {
18087
18088 if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {
18089
18090 object.addEventListener( 'dispose', onInstancedMeshDispose );
18091
18092 }
18093
18094 if ( updateMap.get( object ) !== frame ) {
18095
18096 attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );
18097
18098 if ( object.instanceColor !== null ) {
18099
18100 attributes.update( object.instanceColor, gl.ARRAY_BUFFER );
18101
18102 }
18103
18104 updateMap.set( object, frame );
18105
18106 }
18107
18108 }
18109
18110 if ( object.isSkinnedMesh ) {
18111
18112 const skeleton = object.skeleton;
18113
18114 if ( updateMap.get( skeleton ) !== frame ) {
18115
18116 skeleton.update();
18117
18118 updateMap.set( skeleton, frame );
18119
18120 }
18121
18122 }
18123
18124 return buffergeometry;
18125
18126 }
18127
18128 function dispose() {
18129
18130 updateMap = new WeakMap();
18131
18132 }
18133
18134 function onInstancedMeshDispose( event ) {
18135
18136 const instancedMesh = event.target;
18137
18138 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
18139
18140 attributes.remove( instancedMesh.instanceMatrix );
18141
18142 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );
18143
18144 }
18145
18146 return {
18147
18148 update: update,
18150
18151 };
18152
18153 }
18154
18155 class DepthTexture extends Texture {
18156
18158
18159 format = format !== undefined ? format : DepthFormat;
18160
18161 if ( format !== DepthFormat && format !== DepthStencilFormat ) {
18162
18163 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );
18164
18165 }
18166
18167 if ( type === undefined && format === DepthFormat ) type = UnsignedIntType;
18168 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;
18169
18170 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
18171
18172 this.isDepthTexture = true;
18173
18174 this.image = { width: width, height: height };
18175
18178
18179 this.flipY = false;
18180 this.generateMipmaps = false;
18181
18182 this.compareFunction = null;
18183
18184 }
18185
18186
18187 copy( source ) {
18188
18189 super.copy( source );
18190
18191 this.compareFunction = source.compareFunction;
18192
18193 return this;
18194
18195 }
18196
18197 toJSON( meta ) {
18198
18199 const data = super.toJSON( meta );
18200
18201 if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction;
18202
18203 return data;
18204
18205 }
18206
18207 }
18208
18253 const emptyTexture = /*@__PURE__*/ new Texture();
18254
18255 const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );
18256 emptyShadowTexture.compareFunction = LessEqualCompare;
18257
18258 const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();
18259 const empty3dTexture = /*@__PURE__*/ new Data3DTexture();
18260 const emptyCubeTexture = /*@__PURE__*/ new CubeTexture();
18261
18262 // --- Utilities ---
18263
18264 // Array Caches (provide typed arrays for temporary by size)
18265
18266 const arrayCacheF32 = [];
18267 const arrayCacheI32 = [];
18268
18269 // Float32Array caches used for uploading Matrix uniforms
18270
18271 const mat4array = new Float32Array( 16 );
18272 const mat3array = new Float32Array( 9 );
18273 const mat2array = new Float32Array( 4 );
18274
18275 // Flattening for arrays of vectors and matrices
18276
18277 function flatten( array, nBlocks, blockSize ) {
18278
18279 const firstElem = array[ 0 ];
18280
18281 if ( firstElem <= 0 || firstElem > 0 ) return array;
18282 // unoptimized: ! isNaN( firstElem )
18283 // see http://jacksondunstan.com/articles/983
18284
18285 const n = nBlocks * blockSize;
18286 let r = arrayCacheF32[ n ];
18287
18288 if ( r === undefined ) {
18289
18290 r = new Float32Array( n );
18291 arrayCacheF32[ n ] = r;
18292
18293 }
18294
18295 if ( nBlocks !== 0 ) {
18296
18297 firstElem.toArray( r, 0 );
18298
18299 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {
18300
18301 offset += blockSize;
18302 array[ i ].toArray( r, offset );
18303
18304 }
18305
18306 }
18307
18308 return r;
18309
18310 }
18311
18312 function arraysEqual( a, b ) {
18313
18314 if ( a.length !== b.length ) return false;
18315
18316 for ( let i = 0, l = a.length; i < l; i ++ ) {
18317
18318 if ( a[ i ] !== b[ i ] ) return false;
18319
18320 }
18321
18322 return true;
18323
18324 }
18325
18326 function copyArray( a, b ) {
18327
18328 for ( let i = 0, l = b.length; i < l; i ++ ) {
18329
18330 a[ i ] = b[ i ];
18331
18332 }
18333
18334 }
18335
18336 // Texture unit allocation
18337
18338 function allocTexUnits( textures, n ) {
18339
18340 let r = arrayCacheI32[ n ];
18341
18342 if ( r === undefined ) {
18343
18344 r = new Int32Array( n );
18345 arrayCacheI32[ n ] = r;
18346
18347 }
18348
18349 for ( let i = 0; i !== n; ++ i ) {
18350
18351 r[ i ] = textures.allocateTextureUnit();
18352
18353 }
18354
18355 return r;
18356
18357 }
18358
18359 // --- Setters ---
18360
18361 // Note: Defining these methods externally, because they come in a bunch
18362 // and this way their names minify.
18363
18364 // Single scalar
18365
18366 function setValueV1f( gl, v ) {
18367
18368 const cache = this.cache;
18369
18370 if ( cache[ 0 ] === v ) return;
18371
18372 gl.uniform1f( this.addr, v );
18373
18374 cache[ 0 ] = v;
18375
18376 }
18377
18378 // Single float vector (from flat array or THREE.VectorN)
18379
18380 function setValueV2f( gl, v ) {
18381
18382 const cache = this.cache;
18383
18384 if ( v.x !== undefined ) {
18385
18386 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18387
18388 gl.uniform2f( this.addr, v.x, v.y );
18389
18390 cache[ 0 ] = v.x;
18391 cache[ 1 ] = v.y;
18392
18393 }
18394
18395 } else {
18396
18397 if ( arraysEqual( cache, v ) ) return;
18398
18399 gl.uniform2fv( this.addr, v );
18400
18401 copyArray( cache, v );
18402
18403 }
18404
18405 }
18406
18407 function setValueV3f( gl, v ) {
18408
18409 const cache = this.cache;
18410
18411 if ( v.x !== undefined ) {
18412
18413 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18414
18415 gl.uniform3f( this.addr, v.x, v.y, v.z );
18416
18417 cache[ 0 ] = v.x;
18418 cache[ 1 ] = v.y;
18419 cache[ 2 ] = v.z;
18420
18421 }
18422
18423 } else if ( v.r !== undefined ) {
18424
18425 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {
18426
18427 gl.uniform3f( this.addr, v.r, v.g, v.b );
18428
18429 cache[ 0 ] = v.r;
18430 cache[ 1 ] = v.g;
18431 cache[ 2 ] = v.b;
18432
18433 }
18434
18435 } else {
18436
18437 if ( arraysEqual( cache, v ) ) return;
18438
18439 gl.uniform3fv( this.addr, v );
18440
18441 copyArray( cache, v );
18442
18443 }
18444
18445 }
18446
18447 function setValueV4f( gl, v ) {
18448
18449 const cache = this.cache;
18450
18451 if ( v.x !== undefined ) {
18452
18453 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18454
18455 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
18456
18457 cache[ 0 ] = v.x;
18458 cache[ 1 ] = v.y;
18459 cache[ 2 ] = v.z;
18460 cache[ 3 ] = v.w;
18461
18462 }
18463
18464 } else {
18465
18466 if ( arraysEqual( cache, v ) ) return;
18467
18468 gl.uniform4fv( this.addr, v );
18469
18470 copyArray( cache, v );
18471
18472 }
18473
18474 }
18475
18476 // Single matrix (from flat array or THREE.MatrixN)
18477
18478 function setValueM2( gl, v ) {
18479
18480 const cache = this.cache;
18481 const elements = v.elements;
18482
18483 if ( elements === undefined ) {
18484
18485 if ( arraysEqual( cache, v ) ) return;
18486
18487 gl.uniformMatrix2fv( this.addr, false, v );
18488
18489 copyArray( cache, v );
18490
18491 } else {
18492
18493 if ( arraysEqual( cache, elements ) ) return;
18494
18495 mat2array.set( elements );
18496
18497 gl.uniformMatrix2fv( this.addr, false, mat2array );
18498
18499 copyArray( cache, elements );
18500
18501 }
18502
18503 }
18504
18505 function setValueM3( gl, v ) {
18506
18507 const cache = this.cache;
18508 const elements = v.elements;
18509
18510 if ( elements === undefined ) {
18511
18512 if ( arraysEqual( cache, v ) ) return;
18513
18514 gl.uniformMatrix3fv( this.addr, false, v );
18515
18516 copyArray( cache, v );
18517
18518 } else {
18519
18520 if ( arraysEqual( cache, elements ) ) return;
18521
18522 mat3array.set( elements );
18523
18524 gl.uniformMatrix3fv( this.addr, false, mat3array );
18525
18526 copyArray( cache, elements );
18527
18528 }
18529
18530 }
18531
18532 function setValueM4( gl, v ) {
18533
18534 const cache = this.cache;
18535 const elements = v.elements;
18536
18537 if ( elements === undefined ) {
18538
18539 if ( arraysEqual( cache, v ) ) return;
18540
18541 gl.uniformMatrix4fv( this.addr, false, v );
18542
18543 copyArray( cache, v );
18544
18545 } else {
18546
18547 if ( arraysEqual( cache, elements ) ) return;
18548
18549 mat4array.set( elements );
18550
18551 gl.uniformMatrix4fv( this.addr, false, mat4array );
18552
18553 copyArray( cache, elements );
18554
18555 }
18556
18557 }
18558
18559 // Single integer / boolean
18560
18561 function setValueV1i( gl, v ) {
18562
18563 const cache = this.cache;
18564
18565 if ( cache[ 0 ] === v ) return;
18566
18567 gl.uniform1i( this.addr, v );
18568
18569 cache[ 0 ] = v;
18570
18571 }
18572
18573 // Single integer / boolean vector (from flat array or THREE.VectorN)
18574
18575 function setValueV2i( gl, v ) {
18576
18577 const cache = this.cache;
18578
18579 if ( v.x !== undefined ) {
18580
18581 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18582
18583 gl.uniform2i( this.addr, v.x, v.y );
18584
18585 cache[ 0 ] = v.x;
18586 cache[ 1 ] = v.y;
18587
18588 }
18589
18590 } else {
18591
18592 if ( arraysEqual( cache, v ) ) return;
18593
18594 gl.uniform2iv( this.addr, v );
18595
18596 copyArray( cache, v );
18597
18598 }
18599
18600 }
18601
18602 function setValueV3i( gl, v ) {
18603
18604 const cache = this.cache;
18605
18606 if ( v.x !== undefined ) {
18607
18608 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18609
18610 gl.uniform3i( this.addr, v.x, v.y, v.z );
18611
18612 cache[ 0 ] = v.x;
18613 cache[ 1 ] = v.y;
18614 cache[ 2 ] = v.z;
18615
18616 }
18617
18618 } else {
18619
18620 if ( arraysEqual( cache, v ) ) return;
18621
18622 gl.uniform3iv( this.addr, v );
18623
18624 copyArray( cache, v );
18625
18626 }
18627
18628 }
18629
18630 function setValueV4i( gl, v ) {
18631
18632 const cache = this.cache;
18633
18634 if ( v.x !== undefined ) {
18635
18636 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18637
18638 gl.uniform4i( this.addr, v.x, v.y, v.z, v.w );
18639
18640 cache[ 0 ] = v.x;
18641 cache[ 1 ] = v.y;
18642 cache[ 2 ] = v.z;
18643 cache[ 3 ] = v.w;
18644
18645 }
18646
18647 } else {
18648
18649 if ( arraysEqual( cache, v ) ) return;
18650
18651 gl.uniform4iv( this.addr, v );
18652
18653 copyArray( cache, v );
18654
18655 }
18656
18657 }
18658
18659 // Single unsigned integer
18660
18661 function setValueV1ui( gl, v ) {
18662
18663 const cache = this.cache;
18664
18665 if ( cache[ 0 ] === v ) return;
18666
18667 gl.uniform1ui( this.addr, v );
18668
18669 cache[ 0 ] = v;
18670
18671 }
18672
18673 // Single unsigned integer vector (from flat array or THREE.VectorN)
18674
18675 function setValueV2ui( gl, v ) {
18676
18677 const cache = this.cache;
18678
18679 if ( v.x !== undefined ) {
18680
18681 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {
18682
18683 gl.uniform2ui( this.addr, v.x, v.y );
18684
18685 cache[ 0 ] = v.x;
18686 cache[ 1 ] = v.y;
18687
18688 }
18689
18690 } else {
18691
18692 if ( arraysEqual( cache, v ) ) return;
18693
18694 gl.uniform2uiv( this.addr, v );
18695
18696 copyArray( cache, v );
18697
18698 }
18699
18700 }
18701
18702 function setValueV3ui( gl, v ) {
18703
18704 const cache = this.cache;
18705
18706 if ( v.x !== undefined ) {
18707
18708 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {
18709
18710 gl.uniform3ui( this.addr, v.x, v.y, v.z );
18711
18712 cache[ 0 ] = v.x;
18713 cache[ 1 ] = v.y;
18714 cache[ 2 ] = v.z;
18715
18716 }
18717
18718 } else {
18719
18720 if ( arraysEqual( cache, v ) ) return;
18721
18722 gl.uniform3uiv( this.addr, v );
18723
18724 copyArray( cache, v );
18725
18726 }
18727
18728 }
18729
18730 function setValueV4ui( gl, v ) {
18731
18732 const cache = this.cache;
18733
18734 if ( v.x !== undefined ) {
18735
18736 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {
18737
18738 gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );
18739
18740 cache[ 0 ] = v.x;
18741 cache[ 1 ] = v.y;
18742 cache[ 2 ] = v.z;
18743 cache[ 3 ] = v.w;
18744
18745 }
18746
18747 } else {
18748
18749 if ( arraysEqual( cache, v ) ) return;
18750
18751 gl.uniform4uiv( this.addr, v );
18752
18753 copyArray( cache, v );
18754
18755 }
18756
18757 }
18758
18759
18760 // Single texture (2D / Cube)
18761
18762 function setValueT1( gl, v, textures ) {
18763
18764 const cache = this.cache;
18765 const unit = textures.allocateTextureUnit();
18766
18767 if ( cache[ 0 ] !== unit ) {
18768
18769 gl.uniform1i( this.addr, unit );
18770 cache[ 0 ] = unit;
18771
18772 }
18773
18774 const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture;
18775
18776 textures.setTexture2D( v || emptyTexture2D, unit );
18777
18778 }
18779
18780 function setValueT3D1( gl, v, textures ) {
18781
18782 const cache = this.cache;
18783 const unit = textures.allocateTextureUnit();
18784
18785 if ( cache[ 0 ] !== unit ) {
18786
18787 gl.uniform1i( this.addr, unit );
18788 cache[ 0 ] = unit;
18789
18790 }
18791
18792 textures.setTexture3D( v || empty3dTexture, unit );
18793
18794 }
18795
18796 function setValueT6( gl, v, textures ) {
18797
18798 const cache = this.cache;
18799 const unit = textures.allocateTextureUnit();
18800
18801 if ( cache[ 0 ] !== unit ) {
18802
18803 gl.uniform1i( this.addr, unit );
18804 cache[ 0 ] = unit;
18805
18806 }
18807
18808 textures.setTextureCube( v || emptyCubeTexture, unit );
18809
18810 }
18811
18812 function setValueT2DArray1( gl, v, textures ) {
18813
18814 const cache = this.cache;
18815 const unit = textures.allocateTextureUnit();
18816
18817 if ( cache[ 0 ] !== unit ) {
18818
18819 gl.uniform1i( this.addr, unit );
18820 cache[ 0 ] = unit;
18821
18822 }
18823
18824 textures.setTexture2DArray( v || emptyArrayTexture, unit );
18825
18826 }
18827
18828 // Helper to pick the right setter for the singular case
18829
18830 function getSingularSetter( type ) {
18831
18832 switch ( type ) {
18833
18834 case 0x1406: return setValueV1f; // FLOAT
18835 case 0x8b50: return setValueV2f; // _VEC2
18836 case 0x8b51: return setValueV3f; // _VEC3
18837 case 0x8b52: return setValueV4f; // _VEC4
18838
18839 case 0x8b5a: return setValueM2; // _MAT2
18840 case 0x8b5b: return setValueM3; // _MAT3
18841 case 0x8b5c: return setValueM4; // _MAT4
18842
18843 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
18844 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
18845 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
18846 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4
18847
18848 case 0x1405: return setValueV1ui; // UINT
18849 case 0x8dc6: return setValueV2ui; // _VEC2
18850 case 0x8dc7: return setValueV3ui; // _VEC3
18851 case 0x8dc8: return setValueV4ui; // _VEC4
18852
18853 case 0x8b5e: // SAMPLER_2D
18854 case 0x8d66: // SAMPLER_EXTERNAL_OES
18855 case 0x8dca: // INT_SAMPLER_2D
18856 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
18857 case 0x8b62: // SAMPLER_2D_SHADOW
18858 return setValueT1;
18859
18860 case 0x8b5f: // SAMPLER_3D
18861 case 0x8dcb: // INT_SAMPLER_3D
18862 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
18863 return setValueT3D1;
18864
18865 case 0x8b60: // SAMPLER_CUBE
18866 case 0x8dcc: // INT_SAMPLER_CUBE
18867 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
18868 case 0x8dc5: // SAMPLER_CUBE_SHADOW
18869 return setValueT6;
18870
18871 case 0x8dc1: // SAMPLER_2D_ARRAY
18872 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
18873 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
18874 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
18875 return setValueT2DArray1;
18876
18877 }
18878
18879 }
18880
18881
18882 // Array of scalars
18883
18884 function setValueV1fArray( gl, v ) {
18885
18886 gl.uniform1fv( this.addr, v );
18887
18888 }
18889
18890 // Array of vectors (from flat array or array of THREE.VectorN)
18891
18892 function setValueV2fArray( gl, v ) {
18893
18894 const data = flatten( v, this.size, 2 );
18895
18896 gl.uniform2fv( this.addr, data );
18897
18898 }
18899
18900 function setValueV3fArray( gl, v ) {
18901
18902 const data = flatten( v, this.size, 3 );
18903
18904 gl.uniform3fv( this.addr, data );
18905
18906 }
18907
18908 function setValueV4fArray( gl, v ) {
18909
18910 const data = flatten( v, this.size, 4 );
18911
18912 gl.uniform4fv( this.addr, data );
18913
18914 }
18915
18916 // Array of matrices (from flat array or array of THREE.MatrixN)
18917
18918 function setValueM2Array( gl, v ) {
18919
18920 const data = flatten( v, this.size, 4 );
18921
18922 gl.uniformMatrix2fv( this.addr, false, data );
18923
18924 }
18925
18926 function setValueM3Array( gl, v ) {
18927
18928 const data = flatten( v, this.size, 9 );
18929
18930 gl.uniformMatrix3fv( this.addr, false, data );
18931
18932 }
18933
18934 function setValueM4Array( gl, v ) {
18935
18936 const data = flatten( v, this.size, 16 );
18937
18938 gl.uniformMatrix4fv( this.addr, false, data );
18939
18940 }
18941
18942 // Array of integer / boolean
18943
18944 function setValueV1iArray( gl, v ) {
18945
18946 gl.uniform1iv( this.addr, v );
18947
18948 }
18949
18950 // Array of integer / boolean vectors (from flat array)
18951
18952 function setValueV2iArray( gl, v ) {
18953
18954 gl.uniform2iv( this.addr, v );
18955
18956 }
18957
18958 function setValueV3iArray( gl, v ) {
18959
18960 gl.uniform3iv( this.addr, v );
18961
18962 }
18963
18964 function setValueV4iArray( gl, v ) {
18965
18966 gl.uniform4iv( this.addr, v );
18967
18968 }
18969
18970 // Array of unsigned integer
18971
18972 function setValueV1uiArray( gl, v ) {
18973
18974 gl.uniform1uiv( this.addr, v );
18975
18976 }
18977
18978 // Array of unsigned integer vectors (from flat array)
18979
18980 function setValueV2uiArray( gl, v ) {
18981
18982 gl.uniform2uiv( this.addr, v );
18983
18984 }
18985
18986 function setValueV3uiArray( gl, v ) {
18987
18988 gl.uniform3uiv( this.addr, v );
18989
18990 }
18991
18992 function setValueV4uiArray( gl, v ) {
18993
18994 gl.uniform4uiv( this.addr, v );
18995
18996 }
18997
18998
18999 // Array of textures (2D / 3D / Cube / 2DArray)
19000
19001 function setValueT1Array( gl, v, textures ) {
19002
19003 const cache = this.cache;
19004
19005 const n = v.length;
19006
19007 const units = allocTexUnits( textures, n );
19008
19009 if ( ! arraysEqual( cache, units ) ) {
19010
19011 gl.uniform1iv( this.addr, units );
19012
19013 copyArray( cache, units );
19014
19015 }
19016
19017 for ( let i = 0; i !== n; ++ i ) {
19018
19019 textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
19020
19021 }
19022
19023 }
19024
19025 function setValueT3DArray( gl, v, textures ) {
19026
19027 const cache = this.cache;
19028
19029 const n = v.length;
19030
19031 const units = allocTexUnits( textures, n );
19032
19033 if ( ! arraysEqual( cache, units ) ) {
19034
19035 gl.uniform1iv( this.addr, units );
19036
19037 copyArray( cache, units );
19038
19039 }
19040
19041 for ( let i = 0; i !== n; ++ i ) {
19042
19043 textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );
19044
19045 }
19046
19047 }
19048
19049 function setValueT6Array( gl, v, textures ) {
19050
19051 const cache = this.cache;
19052
19053 const n = v.length;
19054
19055 const units = allocTexUnits( textures, n );
19056
19057 if ( ! arraysEqual( cache, units ) ) {
19058
19059 gl.uniform1iv( this.addr, units );
19060
19061 copyArray( cache, units );
19062
19063 }
19064
19065 for ( let i = 0; i !== n; ++ i ) {
19066
19067 textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
19068
19069 }
19070
19071 }
19072
19073 function setValueT2DArrayArray( gl, v, textures ) {
19074
19075 const cache = this.cache;
19076
19077 const n = v.length;
19078
19079 const units = allocTexUnits( textures, n );
19080
19081 if ( ! arraysEqual( cache, units ) ) {
19082
19083 gl.uniform1iv( this.addr, units );
19084
19085 copyArray( cache, units );
19086
19087 }
19088
19089 for ( let i = 0; i !== n; ++ i ) {
19090
19091 textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );
19092
19093 }
19094
19095 }
19096
19097
19098 // Helper to pick the right setter for a pure (bottom-level) array
19099
19100 function getPureArraySetter( type ) {
19101
19102 switch ( type ) {
19103
19104 case 0x1406: return setValueV1fArray; // FLOAT
19105 case 0x8b50: return setValueV2fArray; // _VEC2
19106 case 0x8b51: return setValueV3fArray; // _VEC3
19107 case 0x8b52: return setValueV4fArray; // _VEC4
19108
19109 case 0x8b5a: return setValueM2Array; // _MAT2
19110 case 0x8b5b: return setValueM3Array; // _MAT3
19111 case 0x8b5c: return setValueM4Array; // _MAT4
19112
19113 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
19114 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
19115 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
19116 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4
19117
19118 case 0x1405: return setValueV1uiArray; // UINT
19119 case 0x8dc6: return setValueV2uiArray; // _VEC2
19120 case 0x8dc7: return setValueV3uiArray; // _VEC3
19121 case 0x8dc8: return setValueV4uiArray; // _VEC4
19122
19123 case 0x8b5e: // SAMPLER_2D
19124 case 0x8d66: // SAMPLER_EXTERNAL_OES
19125 case 0x8dca: // INT_SAMPLER_2D
19126 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
19127 case 0x8b62: // SAMPLER_2D_SHADOW
19128 return setValueT1Array;
19129
19130 case 0x8b5f: // SAMPLER_3D
19131 case 0x8dcb: // INT_SAMPLER_3D
19132 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
19133 return setValueT3DArray;
19134
19135 case 0x8b60: // SAMPLER_CUBE
19136 case 0x8dcc: // INT_SAMPLER_CUBE
19137 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
19138 case 0x8dc5: // SAMPLER_CUBE_SHADOW
19139 return setValueT6Array;
19140
19141 case 0x8dc1: // SAMPLER_2D_ARRAY
19142 case 0x8dcf: // INT_SAMPLER_2D_ARRAY
19143 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
19144 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
19145 return setValueT2DArrayArray;
19146
19147 }
19148
19149 }
19150
19151 // --- Uniform Classes ---
19152
19153 class SingleUniform {
19154
19155 constructor( id, activeInfo, addr ) {
19156
19157 this.id = id;
19158 this.addr = addr;
19159 this.cache = [];
19160 this.type = activeInfo.type;
19161 this.setValue = getSingularSetter( activeInfo.type );
19162
19163 // this.path = activeInfo.name; // DEBUG
19164
19165 }
19166
19167 }
19168
19169 class PureArrayUniform {
19170
19171 constructor( id, activeInfo, addr ) {
19172
19173 this.id = id;
19174 this.addr = addr;
19175 this.cache = [];
19176 this.type = activeInfo.type;
19177 this.size = activeInfo.size;
19178 this.setValue = getPureArraySetter( activeInfo.type );
19179
19180 // this.path = activeInfo.name; // DEBUG
19181
19182 }
19183
19184 }
19185
19186 class StructuredUniform {
19187
19188 constructor( id ) {
19189
19190 this.id = id;
19191
19192 this.seq = [];
19193 this.map = {};
19194
19195 }
19196
19197 setValue( gl, value, textures ) {
19198
19199 const seq = this.seq;
19200
19201 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19202
19203 const u = seq[ i ];
19204 u.setValue( gl, value[ u.id ], textures );
19205
19206 }
19207
19208 }
19209
19210 }
19211
19212 // --- Top-level ---
19213
19214 // Parser - builds up the property tree from the path strings
19215
19216 const RePathPart = /(\w+)(\])?(\[|\.)?/g;
19217
19218 // extracts
19219 // - the identifier (member name or array index)
19220 // - followed by an optional right bracket (found when array index)
19221 // - followed by an optional left bracket or dot (type of subscript)
19222 //
19223 // Note: These portions can be read in a non-overlapping fashion and
19224 // allow straightforward parsing of the hierarchy that WebGL encodes
19225 // in the uniform names.
19226
19227 function addUniform( container, uniformObject ) {
19228
19229 container.seq.push( uniformObject );
19231
19232 }
19233
19234 function parseUniform( activeInfo, addr, container ) {
19235
19236 const path = activeInfo.name,
19237 pathLength = path.length;
19238
19239 // reset RegExp object, because of the early exit of a previous run
19240 RePathPart.lastIndex = 0;
19241
19242 while ( true ) {
19243
19244 const match = RePathPart.exec( path ),
19245 matchEnd = RePathPart.lastIndex;
19246
19247 let id = match[ 1 ];
19248 const idIsIndex = match[ 2 ] === ']',
19249 subscript = match[ 3 ];
19250
19251 if ( idIsIndex ) id = id | 0; // convert to integer
19252
19253 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
19254
19255 // bare name or "pure" bottom-level array "[0]" suffix
19256
19258 new SingleUniform( id, activeInfo, addr ) :
19260
19261 break;
19262
19263 } else {
19264
19265 // step into inner node / create it in case it doesn't exist
19266
19267 const map = container.map;
19268 let next = map[ id ];
19269
19270 if ( next === undefined ) {
19271
19272 next = new StructuredUniform( id );
19274
19275 }
19276
19277 container = next;
19278
19279 }
19280
19281 }
19282
19283 }
19284
19285 // Root Container
19286
19287 class WebGLUniforms {
19288
19289 constructor( gl, program ) {
19290
19291 this.seq = [];
19292 this.map = {};
19293
19294 const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
19295
19296 for ( let i = 0; i < n; ++ i ) {
19297
19298 const info = gl.getActiveUniform( program, i ),
19299 addr = gl.getUniformLocation( program, info.name );
19300
19301 parseUniform( info, addr, this );
19302
19303 }
19304
19305 }
19306
19307 setValue( gl, name, value, textures ) {
19308
19309 const u = this.map[ name ];
19310
19311 if ( u !== undefined ) u.setValue( gl, value, textures );
19312
19313 }
19314
19315 setOptional( gl, object, name ) {
19316
19317 const v = object[ name ];
19318
19319 if ( v !== undefined ) this.setValue( gl, name, v );
19320
19321 }
19322
19323 static upload( gl, seq, values, textures ) {
19324
19325 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19326
19327 const u = seq[ i ],
19328 v = values[ u.id ];
19329
19330 if ( v.needsUpdate !== false ) {
19331
19332 // note: always updating when .needsUpdate is undefined
19333 u.setValue( gl, v.value, textures );
19334
19335 }
19336
19337 }
19338
19339 }
19340
19341 static seqWithValue( seq, values ) {
19342
19343 const r = [];
19344
19345 for ( let i = 0, n = seq.length; i !== n; ++ i ) {
19346
19347 const u = seq[ i ];
19348 if ( u.id in values ) r.push( u );
19349
19350 }
19351
19352 return r;
19353
19354 }
19355
19356 }
19357
19358 function WebGLShader( gl, type, string ) {
19359
19360 const shader = gl.createShader( type );
19361
19362 gl.shaderSource( shader, string );
19363 gl.compileShader( shader );
19364
19365 return shader;
19366
19367 }
19368
19369 // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
19370 const COMPLETION_STATUS_KHR = 0x91B1;
19371
19372 let programIdCount = 0;
19373
19374 function handleSource( string, errorLine ) {
19375
19376 const lines = string.split( '\n' );
19377 const lines2 = [];
19378
19379 const from = Math.max( errorLine - 6, 0 );
19380 const to = Math.min( errorLine + 6, lines.length );
19381
19382 for ( let i = from; i < to; i ++ ) {
19383
19384 const line = i + 1;
19385 lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );
19386
19387 }
19388
19389 return lines2.join( '\n' );
19390
19391 }
19392
19393 function getEncodingComponents( colorSpace ) {
19394
19395 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
19396 const encodingPrimaries = ColorManagement.getPrimaries( colorSpace );
19397
19399
19401
19402 gamutMapping = '';
19403
19405
19406 gamutMapping = 'LinearDisplayP3ToLinearSRGB';
19407
19409
19410 gamutMapping = 'LinearSRGBToLinearDisplayP3';
19411
19412 }
19413
19414 switch ( colorSpace ) {
19415
19418 return [ gamutMapping, 'LinearTransferOETF' ];
19419
19420 case SRGBColorSpace:
19422 return [ gamutMapping, 'sRGBTransferOETF' ];
19423
19424 default:
19425 console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );
19426 return [ gamutMapping, 'LinearTransferOETF' ];
19427
19428 }
19429
19430 }
19431
19432 function getShaderErrors( gl, shader, type ) {
19433
19434 const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );
19435 const errors = gl.getShaderInfoLog( shader ).trim();
19436
19437 if ( status && errors === '' ) return '';
19438
19439 const errorMatches = /ERROR: 0:(\d+)/.exec( errors );
19440 if ( errorMatches ) {
19441
19442 // --enable-privileged-webgl-extension
19443 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
19444
19445 const errorLine = parseInt( errorMatches[ 1 ] );
19446 return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine );
19447
19448 } else {
19449
19450 return errors;
19451
19452 }
19453
19454 }
19455
19457
19459 return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;
19460
19461 }
19462
19464
19466
19467 switch ( toneMapping ) {
19468
19469 case LinearToneMapping:
19470 toneMappingName = 'Linear';
19471 break;
19472
19474 toneMappingName = 'Reinhard';
19475 break;
19476
19477 case CineonToneMapping:
19478 toneMappingName = 'OptimizedCineon';
19479 break;
19480
19482 toneMappingName = 'ACESFilmic';
19483 break;
19484
19485 case AgXToneMapping:
19486 toneMappingName = 'AgX';
19487 break;
19488
19489 case CustomToneMapping:
19490 toneMappingName = 'Custom';
19491 break;
19492
19493 default:
19494 console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
19495 toneMappingName = 'Linear';
19496
19497 }
19498
19499 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
19500
19501 }
19502
19503 function generateExtensions( parameters ) {
19504
19505 const chunks = [
19506 ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
19507 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
19508 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
19509 ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
19510 ];
19511
19512 return chunks.filter( filterEmptyLine ).join( '\n' );
19513
19514 }
19515
19517
19518 const chunks = [
19519 parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : ''
19520 ];
19521
19522 return chunks.filter( filterEmptyLine ).join( '\n' );
19523
19524 }
19525
19526 function generateDefines( defines ) {
19527
19528 const chunks = [];
19529
19530 for ( const name in defines ) {
19531
19532 const value = defines[ name ];
19533
19534 if ( value === false ) continue;
19535
19536 chunks.push( '#define ' + name + ' ' + value );
19537
19538 }
19539
19540 return chunks.join( '\n' );
19541
19542 }
19543
19544 function fetchAttributeLocations( gl, program ) {
19545
19546 const attributes = {};
19547
19548 const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
19549
19550 for ( let i = 0; i < n; i ++ ) {
19551
19552 const info = gl.getActiveAttrib( program, i );
19553 const name = info.name;
19554
19555 let locationSize = 1;
19556 if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
19557 if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
19558 if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;
19559
19560 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
19561
19562 attributes[ name ] = {
19563 type: info.type,
19564 location: gl.getAttribLocation( program, name ),
19566 };
19567
19568 }
19569
19570 return attributes;
19571
19572 }
19573
19574 function filterEmptyLine( string ) {
19575
19576 return string !== '';
19577
19578 }
19579
19580 function replaceLightNums( string, parameters ) {
19581
19582 const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;
19583
19584 return string
19585 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
19586 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
19587 .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
19589 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
19590 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
19591 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
19592 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
19593 .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )
19594 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
19595 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
19596
19597 }
19598
19599 function replaceClippingPlaneNums( string, parameters ) {
19600
19601 return string
19602 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
19603 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
19604
19605 }
19606
19607 // Resolve Includes
19608
19609 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
19610
19611 function resolveIncludes( string ) {
19612
19613 return string.replace( includePattern, includeReplacer );
19614
19615 }
19616
19617 const shaderChunkMap = new Map( [
19618 [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154
19619 [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154
19620 [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154
19621 ] );
19622
19623 function includeReplacer( match, include ) {
19624
19625 let string = ShaderChunk[ include ];
19626
19627 if ( string === undefined ) {
19628
19629 const newInclude = shaderChunkMap.get( include );
19630
19631 if ( newInclude !== undefined ) {
19632
19633 string = ShaderChunk[ newInclude ];
19634 console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude );
19635
19636 } else {
19637
19638 throw new Error( 'Can not resolve #include <' + include + '>' );
19639
19640 }
19641
19642 }
19643
19644 return resolveIncludes( string );
19645
19646 }
19647
19648 // Unroll Loops
19649
19650 const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\‍(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\‍)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
19651
19652 function unrollLoops( string ) {
19653
19654 return string.replace( unrollLoopPattern, loopReplacer );
19655
19656 }
19657
19658 function loopReplacer( match, start, end, snippet ) {
19659
19660 let string = '';
19661
19662 for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
19663
19664 string += snippet
19665 .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
19666 .replace( /UNROLLED_LOOP_INDEX/g, i );
19667
19668 }
19669
19670 return string;
19671
19672 }
19673
19674 //
19675
19676 function generatePrecision( parameters ) {
19677
19678 let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;';
19679
19680 if ( parameters.precision === 'highp' ) {
19681
19682 precisionstring += '\n#define HIGH_PRECISION';
19683
19684 } else if ( parameters.precision === 'mediump' ) {
19685
19686 precisionstring += '\n#define MEDIUM_PRECISION';
19687
19688 } else if ( parameters.precision === 'lowp' ) {
19689
19690 precisionstring += '\n#define LOW_PRECISION';
19691
19692 }
19693
19694 return precisionstring;
19695
19696 }
19697
19699
19700 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
19701
19702 if ( parameters.shadowMapType === PCFShadowMap ) {
19703
19704 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
19705
19706 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
19707
19708 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
19709
19710 } else if ( parameters.shadowMapType === VSMShadowMap ) {
19711
19712 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
19713
19714 }
19715
19716 return shadowMapTypeDefine;
19717
19718 }
19719
19721
19722 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19723
19724 if ( parameters.envMap ) {
19725
19726 switch ( parameters.envMapMode ) {
19727
19730 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19731 break;
19732
19734 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
19735 break;
19736
19737 }
19738
19739 }
19740
19741 return envMapTypeDefine;
19742
19743 }
19744
19746
19747 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
19748
19749 if ( parameters.envMap ) {
19750
19751 switch ( parameters.envMapMode ) {
19752
19754
19755 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
19756 break;
19757
19758 }
19759
19760 }
19761
19762 return envMapModeDefine;
19763
19764 }
19765
19767
19768 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
19769
19770 if ( parameters.envMap ) {
19771
19772 switch ( parameters.combine ) {
19773
19774 case MultiplyOperation:
19775 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
19776 break;
19777
19778 case MixOperation:
19779 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
19780 break;
19781
19782 case AddOperation:
19783 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
19784 break;
19785
19786 }
19787
19788 }
19789
19790 return envMapBlendingDefine;
19791
19792 }
19793
19794 function generateCubeUVSize( parameters ) {
19795
19796 const imageHeight = parameters.envMapCubeUVHeight;
19797
19798 if ( imageHeight === null ) return null;
19799
19800 const maxMip = Math.log2( imageHeight ) - 2;
19801
19802 const texelHeight = 1.0 / imageHeight;
19803
19804 const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
19805
19806 return { texelWidth, texelHeight, maxMip };
19807
19808 }
19809
19810 function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
19811
19812 // TODO Send this event to Three.js DevTools
19813 // console.log( 'WebGLProgram', cacheKey );
19814
19815 const gl = renderer.getContext();
19816
19817 const defines = parameters.defines;
19818
19819 let vertexShader = parameters.vertexShader;
19820 let fragmentShader = parameters.fragmentShader;
19821
19827
19828 const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
19829
19831
19833
19834 const program = gl.createProgram();
19835
19837 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
19838
19839 if ( parameters.isRawShaderMaterial ) {
19840
19841 prefixVertex = [
19842
19843 '#define SHADER_TYPE ' + parameters.shaderType,
19844 '#define SHADER_NAME ' + parameters.shaderName,
19845
19847
19848 ].filter( filterEmptyLine ).join( '\n' );
19849
19850 if ( prefixVertex.length > 0 ) {
19851
19852 prefixVertex += '\n';
19853
19854 }
19855
19856 prefixFragment = [
19857
19859
19860 '#define SHADER_TYPE ' + parameters.shaderType,
19861 '#define SHADER_NAME ' + parameters.shaderName,
19862
19864
19865 ].filter( filterEmptyLine ).join( '\n' );
19866
19867 if ( prefixFragment.length > 0 ) {
19868
19869 prefixFragment += '\n';
19870
19871 }
19872
19873 } else {
19874
19875 prefixVertex = [
19876
19878
19879 '#define SHADER_TYPE ' + parameters.shaderType,
19880 '#define SHADER_NAME ' + parameters.shaderName,
19881
19883
19884 parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
19885 parameters.batching ? '#define USE_BATCHING' : '',
19886 parameters.instancing ? '#define USE_INSTANCING' : '',
19887 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
19888
19889 parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
19890 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
19891
19892 parameters.map ? '#define USE_MAP' : '',
19893 parameters.envMap ? '#define USE_ENVMAP' : '',
19894 parameters.envMap ? '#define ' + envMapModeDefine : '',
19895 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
19896 parameters.aoMap ? '#define USE_AOMAP' : '',
19897 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
19898 parameters.normalMap ? '#define USE_NORMALMAP' : '',
19899 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
19900 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
19901 parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',
19902 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
19903
19904 parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
19905 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
19906
19907 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
19908 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
19909 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
19910
19911 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
19912 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
19913
19914 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
19915 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
19916 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
19917
19918 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
19919 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
19920 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
19921 parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
19922
19923 parameters.transmission ? '#define USE_TRANSMISSION' : '',
19924 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
19925 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
19926
19927 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
19928 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
19929
19930 //
19931
19932 parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',
19933 parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',
19934 parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',
19935 parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',
19936 parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',
19937 parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',
19938 parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',
19939 parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',
19940
19941 parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',
19942 parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',
19943
19944 parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',
19945
19946 parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',
19947 parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',
19948 parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',
19949
19950 parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',
19951 parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',
19952
19953 parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',
19954 parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',
19955
19956 parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',
19957 parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',
19958 parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',
19959
19960 parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',
19961 parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',
19962
19963 //
19964
19965 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
19966 parameters.vertexColors ? '#define USE_COLOR' : '',
19967 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
19968 parameters.vertexUv1s ? '#define USE_UV1' : '',
19969 parameters.vertexUv2s ? '#define USE_UV2' : '',
19970 parameters.vertexUv3s ? '#define USE_UV3' : '',
19971
19972 parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
19973
19974 parameters.flatShading ? '#define FLAT_SHADED' : '',
19975
19976 parameters.skinning ? '#define USE_SKINNING' : '',
19977
19978 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
19979 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
19980 ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '',
19981 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
19982 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
19983 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
19984 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
19985 parameters.flipSided ? '#define FLIP_SIDED' : '',
19986
19987 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
19989
19990 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
19991
19992 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
19993
19994 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
19995
19996 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
19997 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
19998
19999 'uniform mat4 modelMatrix;',
20000 'uniform mat4 modelViewMatrix;',
20001 'uniform mat4 projectionMatrix;',
20002 'uniform mat4 viewMatrix;',
20003 'uniform mat3 normalMatrix;',
20004 'uniform vec3 cameraPosition;',
20005 'uniform bool isOrthographic;',
20006
20007 '#ifdef USE_INSTANCING',
20008
20009 ' attribute mat4 instanceMatrix;',
20010
20011 '#endif',
20012
20013 '#ifdef USE_INSTANCING_COLOR',
20014
20015 ' attribute vec3 instanceColor;',
20016
20017 '#endif',
20018
20019 'attribute vec3 position;',
20020 'attribute vec3 normal;',
20021 'attribute vec2 uv;',
20022
20023 '#ifdef USE_UV1',
20024
20025 ' attribute vec2 uv1;',
20026
20027 '#endif',
20028
20029 '#ifdef USE_UV2',
20030
20031 ' attribute vec2 uv2;',
20032
20033 '#endif',
20034
20035 '#ifdef USE_UV3',
20036
20037 ' attribute vec2 uv3;',
20038
20039 '#endif',
20040
20041 '#ifdef USE_TANGENT',
20042
20043 ' attribute vec4 tangent;',
20044
20045 '#endif',
20046
20047 '#if defined( USE_COLOR_ALPHA )',
20048
20049 ' attribute vec4 color;',
20050
20051 '#elif defined( USE_COLOR )',
20052
20053 ' attribute vec3 color;',
20054
20055 '#endif',
20056
20057 '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
20058
20059 ' attribute vec3 morphTarget0;',
20060 ' attribute vec3 morphTarget1;',
20061 ' attribute vec3 morphTarget2;',
20062 ' attribute vec3 morphTarget3;',
20063
20064 ' #ifdef USE_MORPHNORMALS',
20065
20066 ' attribute vec3 morphNormal0;',
20067 ' attribute vec3 morphNormal1;',
20068 ' attribute vec3 morphNormal2;',
20069 ' attribute vec3 morphNormal3;',
20070
20071 ' #else',
20072
20073 ' attribute vec3 morphTarget4;',
20074 ' attribute vec3 morphTarget5;',
20075 ' attribute vec3 morphTarget6;',
20076 ' attribute vec3 morphTarget7;',
20077
20078 ' #endif',
20079
20080 '#endif',
20081
20082 '#ifdef USE_SKINNING',
20083
20084 ' attribute vec4 skinIndex;',
20085 ' attribute vec4 skinWeight;',
20086
20087 '#endif',
20088
20089 '\n'
20090
20091 ].filter( filterEmptyLine ).join( '\n' );
20092
20093 prefixFragment = [
20094
20096
20098
20099 '#define SHADER_TYPE ' + parameters.shaderType,
20100 '#define SHADER_NAME ' + parameters.shaderName,
20101
20103
20104 parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
20105 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
20106
20107 parameters.map ? '#define USE_MAP' : '',
20108 parameters.matcap ? '#define USE_MATCAP' : '',
20109 parameters.envMap ? '#define USE_ENVMAP' : '',
20110 parameters.envMap ? '#define ' + envMapTypeDefine : '',
20111 parameters.envMap ? '#define ' + envMapModeDefine : '',
20112 parameters.envMap ? '#define ' + envMapBlendingDefine : '',
20113 envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
20114 envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
20115 envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
20116 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
20117 parameters.aoMap ? '#define USE_AOMAP' : '',
20118 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
20119 parameters.normalMap ? '#define USE_NORMALMAP' : '',
20120 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
20121 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
20122 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
20123
20124 parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
20125 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
20126
20127 parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
20128 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
20129 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
20130 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
20131
20132 parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
20133 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
20134 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
20135
20136 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
20137 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
20138 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
20139
20140 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
20141 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
20142
20143 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
20144 parameters.alphaTest ? '#define USE_ALPHATEST' : '',
20145 parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
20146
20147 parameters.sheen ? '#define USE_SHEEN' : '',
20148 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
20149 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
20150
20151 parameters.transmission ? '#define USE_TRANSMISSION' : '',
20152 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
20153 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
20154
20155 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
20156 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
20157 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
20158 parameters.vertexUv1s ? '#define USE_UV1' : '',
20159 parameters.vertexUv2s ? '#define USE_UV2' : '',
20160 parameters.vertexUv3s ? '#define USE_UV3' : '',
20161
20162 parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
20163
20164 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
20165
20166 parameters.flatShading ? '#define FLAT_SHADED' : '',
20167
20168 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
20169 parameters.flipSided ? '#define FLIP_SIDED' : '',
20170
20171 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
20172 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
20173
20174 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
20175
20176 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
20177
20178 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
20179
20180 parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
20181
20182 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
20183 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
20184
20185 'uniform mat4 viewMatrix;',
20186 'uniform vec3 cameraPosition;',
20187 'uniform bool isOrthographic;',
20188
20189 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
20190 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
20192
20193 parameters.dithering ? '#define DITHERING' : '',
20194 parameters.opaque ? '#define OPAQUE' : '',
20195
20196 ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
20197 getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),
20198
20199 parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
20200
20201 '\n'
20202
20203 ].filter( filterEmptyLine ).join( '\n' );
20204
20205 }
20206
20210
20214
20217
20218 if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
20219
20220 // GLSL 3.0 conversion for built-in materials and ShaderMaterial
20221
20222 versionString = '#version 300 es\n';
20223
20224 prefixVertex = [
20226 'precision mediump sampler2DArray;',
20227 '#define attribute in',
20228 '#define varying out',
20229 '#define texture2D texture'
20230 ].join( '\n' ) + '\n' + prefixVertex;
20231
20232 prefixFragment = [
20233 'precision mediump sampler2DArray;',
20234 '#define varying in',
20235 ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
20236 ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
20237 '#define gl_FragDepthEXT gl_FragDepth',
20238 '#define texture2D texture',
20239 '#define textureCube texture',
20240 '#define texture2DProj textureProj',
20241 '#define texture2DLodEXT textureLod',
20242 '#define texture2DProjLodEXT textureProjLod',
20243 '#define textureCubeLodEXT textureLod',
20244 '#define texture2DGradEXT textureGrad',
20245 '#define texture2DProjGradEXT textureProjGrad',
20246 '#define textureCubeGradEXT textureGrad'
20247 ].join( '\n' ) + '\n' + prefixFragment;
20248
20249 }
20250
20253
20254 // console.log( '*VERTEX*', vertexGlsl );
20255 // console.log( '*FRAGMENT*', fragmentGlsl );
20256
20257 const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
20258 const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
20259
20260 gl.attachShader( program, glVertexShader );
20261 gl.attachShader( program, glFragmentShader );
20262
20263 // Force a particular attribute to index 0.
20264
20265 if ( parameters.index0AttributeName !== undefined ) {
20266
20267 gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
20268
20269 } else if ( parameters.morphTargets === true ) {
20270
20271 // programs with morphTargets displace position out of attribute 0
20272 gl.bindAttribLocation( program, 0, 'position' );
20273
20274 }
20275
20276 gl.linkProgram( program );
20277
20278 function onFirstUse( self ) {
20279
20280 // check for link errors
20281 if ( renderer.debug.checkShaderErrors ) {
20282
20283 const programLog = gl.getProgramInfoLog( program ).trim();
20284 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
20285 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
20286
20287 let runnable = true;
20288 let haveDiagnostics = true;
20289
20290 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
20291
20292 runnable = false;
20293
20294 if ( typeof renderer.debug.onShaderError === 'function' ) {
20295
20296 renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );
20297
20298 } else {
20299
20300 // default error reporting
20301
20302 const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
20303 const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
20304
20305 console.error(
20306 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
20307 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
20308 'Program Info Log: ' + programLog + '\n' +
20309 vertexErrors + '\n' +
20311 );
20312
20313 }
20314
20315 } else if ( programLog !== '' ) {
20316
20317 console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );
20318
20319 } else if ( vertexLog === '' || fragmentLog === '' ) {
20320
20321 haveDiagnostics = false;
20322
20323 }
20324
20325 if ( haveDiagnostics ) {
20326
20327 self.diagnostics = {
20328
20330
20332
20333 vertexShader: {
20334
20335 log: vertexLog,
20337
20338 },
20339
20341
20344
20345 }
20346
20347 };
20348
20349 }
20350
20351 }
20352
20353 // Clean up
20354
20355 // Crashes in iOS9 and iOS10. #18402
20356 // gl.detachShader( program, glVertexShader );
20357 // gl.detachShader( program, glFragmentShader );
20358
20359 gl.deleteShader( glVertexShader );
20360 gl.deleteShader( glFragmentShader );
20361
20364
20365 }
20366
20367 // set up caching for uniform locations
20368
20370
20371 this.getUniforms = function () {
20372
20373 if ( cachedUniforms === undefined ) {
20374
20375 // Populates cachedUniforms and cachedAttributes
20376 onFirstUse( this );
20377
20378 }
20379
20380 return cachedUniforms;
20381
20382 };
20383
20384 // set up caching for attribute locations
20385
20387
20388 this.getAttributes = function () {
20389
20390 if ( cachedAttributes === undefined ) {
20391
20392 // Populates cachedAttributes and cachedUniforms
20393 onFirstUse( this );
20394
20395 }
20396
20397 return cachedAttributes;
20398
20399 };
20400
20401 // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,
20402 // flag the program as ready immediately. It may cause a stall when it's first used.
20403
20404 let programReady = ( parameters.rendererExtensionParallelShaderCompile === false );
20405
20406 this.isReady = function () {
20407
20408 if ( programReady === false ) {
20409
20410 programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );
20411
20412 }
20413
20414 return programReady;
20415
20416 };
20417
20418 // free resource
20419
20420 this.destroy = function () {
20421
20422 bindingStates.releaseStatesOfProgram( this );
20423
20424 gl.deleteProgram( program );
20425 this.program = undefined;
20426
20427 };
20428
20429 //
20430
20431 this.type = parameters.shaderType;
20432 this.name = parameters.shaderName;
20433 this.id = programIdCount ++;
20434 this.cacheKey = cacheKey;
20435 this.usedTimes = 1;
20436 this.program = program;
20437 this.vertexShader = glVertexShader;
20438 this.fragmentShader = glFragmentShader;
20439
20440 return this;
20441
20442 }
20443
20444 let _id$1 = 0;
20445
20446 class WebGLShaderCache {
20447
20448 constructor() {
20449
20450 this.shaderCache = new Map();
20451 this.materialCache = new Map();
20452
20453 }
20454
20455 update( material ) {
20456
20457 const vertexShader = material.vertexShader;
20458 const fragmentShader = material.fragmentShader;
20459
20460 const vertexShaderStage = this._getShaderStage( vertexShader );
20461 const fragmentShaderStage = this._getShaderStage( fragmentShader );
20462
20464
20465 if ( materialShaders.has( vertexShaderStage ) === false ) {
20466
20468 vertexShaderStage.usedTimes ++;
20469
20470 }
20471
20472 if ( materialShaders.has( fragmentShaderStage ) === false ) {
20473
20475 fragmentShaderStage.usedTimes ++;
20476
20477 }
20478
20479 return this;
20480
20481 }
20482
20483 remove( material ) {
20484
20485 const materialShaders = this.materialCache.get( material );
20486
20487 for ( const shaderStage of materialShaders ) {
20488
20489 shaderStage.usedTimes --;
20490
20491 if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );
20492
20493 }
20494
20495 this.materialCache.delete( material );
20496
20497 return this;
20498
20499 }
20500
20502
20503 return this._getShaderStage( material.vertexShader ).id;
20504
20505 }
20506
20508
20509 return this._getShaderStage( material.fragmentShader ).id;
20510
20511 }
20512
20513 dispose() {
20514
20515 this.shaderCache.clear();
20516 this.materialCache.clear();
20517
20518 }
20519
20521
20522 const cache = this.materialCache;
20523 let set = cache.get( material );
20524
20525 if ( set === undefined ) {
20526
20527 set = new Set();
20528 cache.set( material, set );
20529
20530 }
20531
20532 return set;
20533
20534 }
20535
20537
20538 const cache = this.shaderCache;
20539 let stage = cache.get( code );
20540
20541 if ( stage === undefined ) {
20542
20543 stage = new WebGLShaderStage( code );
20544 cache.set( code, stage );
20545
20546 }
20547
20548 return stage;
20549
20550 }
20551
20552 }
20553
20554 class WebGLShaderStage {
20555
20556 constructor( code ) {
20557
20558 this.id = _id$1 ++;
20559
20560 this.code = code;
20561 this.usedTimes = 0;
20562
20563 }
20564
20565 }
20566
20568
20569 const _programLayers = new Layers();
20570 const _customShaders = new WebGLShaderCache();
20571 const programs = [];
20572
20573 const IS_WEBGL2 = capabilities.isWebGL2;
20574 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
20575 const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;
20576
20577 let precision = capabilities.precision;
20578
20579 const shaderIDs = {
20580 MeshDepthMaterial: 'depth',
20581 MeshDistanceMaterial: 'distanceRGBA',
20582 MeshNormalMaterial: 'normal',
20583 MeshBasicMaterial: 'basic',
20584 MeshLambertMaterial: 'lambert',
20585 MeshPhongMaterial: 'phong',
20586 MeshToonMaterial: 'toon',
20587 MeshStandardMaterial: 'physical',
20588 MeshPhysicalMaterial: 'physical',
20589 MeshMatcapMaterial: 'matcap',
20590 LineBasicMaterial: 'basic',
20591 LineDashedMaterial: 'dashed',
20592 PointsMaterial: 'points',
20593 ShadowMaterial: 'shadow',
20594 SpriteMaterial: 'sprite'
20595 };
20596
20597 function getChannel( value ) {
20598
20599 if ( value === 0 ) return 'uv';
20600
20601 return `uv${ value }`;
20602
20603 }
20604
20605 function getParameters( material, lights, shadows, scene, object ) {
20606
20607 const fog = scene.fog;
20608 const geometry = object.geometry;
20609 const environment = material.isMeshStandardMaterial ? scene.environment : null;
20610
20611 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
20612 const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;
20613
20614 const shaderID = shaderIDs[ material.type ];
20615
20616 // heuristics to create shader parameters according to lights in the scene
20617 // (not to blow over maxLights budget)
20618
20619 if ( material.precision !== null ) {
20620
20621 precision = capabilities.getMaxPrecision( material.precision );
20622
20623 if ( precision !== material.precision ) {
20624
20625 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
20626
20627 }
20628
20629 }
20630
20631 //
20632
20633 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
20634 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
20635
20637
20638 if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
20639 if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
20640 if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;
20641
20642 //
20643
20646
20647 if ( shaderID ) {
20648
20649 const shader = ShaderLib[ shaderID ];
20650
20651 vertexShader = shader.vertexShader;
20652 fragmentShader = shader.fragmentShader;
20653
20654 } else {
20655
20656 vertexShader = material.vertexShader;
20657 fragmentShader = material.fragmentShader;
20658
20659 _customShaders.update( material );
20660
20661 customVertexShaderID = _customShaders.getVertexShaderID( material );
20662 customFragmentShaderID = _customShaders.getFragmentShaderID( material );
20663
20664 }
20665
20666 const currentRenderTarget = renderer.getRenderTarget();
20667
20668 const IS_INSTANCEDMESH = object.isInstancedMesh === true;
20669 const IS_BATCHEDMESH = object.isBatchedMesh === true;
20670
20671 const HAS_MAP = !! material.map;
20672 const HAS_MATCAP = !! material.matcap;
20673 const HAS_ENVMAP = !! envMap;
20674 const HAS_AOMAP = !! material.aoMap;
20675 const HAS_LIGHTMAP = !! material.lightMap;
20676 const HAS_BUMPMAP = !! material.bumpMap;
20677 const HAS_NORMALMAP = !! material.normalMap;
20678 const HAS_DISPLACEMENTMAP = !! material.displacementMap;
20679 const HAS_EMISSIVEMAP = !! material.emissiveMap;
20680
20681 const HAS_METALNESSMAP = !! material.metalnessMap;
20682 const HAS_ROUGHNESSMAP = !! material.roughnessMap;
20683
20684 const HAS_ANISOTROPY = material.anisotropy > 0;
20685 const HAS_CLEARCOAT = material.clearcoat > 0;
20686 const HAS_IRIDESCENCE = material.iridescence > 0;
20687 const HAS_SHEEN = material.sheen > 0;
20688 const HAS_TRANSMISSION = material.transmission > 0;
20689
20690 const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap;
20691
20692 const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap;
20693 const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap;
20694 const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap;
20695
20696 const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap;
20697 const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap;
20698
20699 const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap;
20700 const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap;
20701
20702 const HAS_SPECULARMAP = !! material.specularMap;
20703 const HAS_SPECULAR_COLORMAP = !! material.specularColorMap;
20704 const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap;
20705
20706 const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap;
20707 const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap;
20708
20709 const HAS_GRADIENTMAP = !! material.gradientMap;
20710
20711 const HAS_ALPHAMAP = !! material.alphaMap;
20712
20713 const HAS_ALPHATEST = material.alphaTest > 0;
20714
20715 const HAS_ALPHAHASH = !! material.alphaHash;
20716
20717 const HAS_EXTENSIONS = !! material.extensions;
20718
20719 const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1;
20720 const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2;
20721 const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3;
20722
20724
20725 if ( material.toneMapped ) {
20726
20727 if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {
20728
20729 toneMapping = renderer.toneMapping;
20730
20731 }
20732
20733 }
20734
20735 const parameters = {
20736
20738
20740 shaderType: material.type,
20741 shaderName: material.name,
20742
20745 defines: material.defines,
20746
20749
20750 isRawShaderMaterial: material.isRawShaderMaterial === true,
20751 glslVersion: material.glslVersion,
20752
20754
20757 instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
20758
20761
20762 map: HAS_MAP,
20773
20776
20779
20782
20787
20791
20795
20799
20803
20805
20807
20811
20813
20814 //
20815
20823
20826
20828
20832
20835
20838
20842
20845
20847
20848 //
20849
20856
20858
20859 fog: !! fog,
20860 useFog: material.fog === true,
20861 fogExp2: ( fog && fog.isFogExp2 ),
20862
20864
20867
20869
20875
20882
20887
20889
20892
20894
20896 shadowMapType: renderer.shadowMap.type,
20897
20900
20902
20904
20907
20910
20912
20918
20919 rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ),
20920 rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ),
20921 rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ),
20922 rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),
20923
20925
20926 };
20927
20928 return parameters;
20929
20930 }
20931
20932 function getProgramCacheKey( parameters ) {
20933
20934 const array = [];
20935
20936 if ( parameters.shaderID ) {
20937
20938 array.push( parameters.shaderID );
20939
20940 } else {
20941
20942 array.push( parameters.customVertexShaderID );
20943 array.push( parameters.customFragmentShaderID );
20944
20945 }
20946
20947 if ( parameters.defines !== undefined ) {
20948
20949 for ( const name in parameters.defines ) {
20950
20951 array.push( name );
20952 array.push( parameters.defines[ name ] );
20953
20954 }
20955
20956 }
20957
20958 if ( parameters.isRawShaderMaterial === false ) {
20959
20962 array.push( renderer.outputColorSpace );
20963
20964 }
20965
20966 array.push( parameters.customProgramCacheKey );
20967
20968 return array.join();
20969
20970 }
20971
20973
20974 array.push( parameters.precision );
20975 array.push( parameters.outputColorSpace );
20976 array.push( parameters.envMapMode );
20977 array.push( parameters.envMapCubeUVHeight );
20978 array.push( parameters.mapUv );
20979 array.push( parameters.alphaMapUv );
20980 array.push( parameters.lightMapUv );
20981 array.push( parameters.aoMapUv );
20982 array.push( parameters.bumpMapUv );
20983 array.push( parameters.normalMapUv );
20984 array.push( parameters.displacementMapUv );
20985 array.push( parameters.emissiveMapUv );
20986 array.push( parameters.metalnessMapUv );
20987 array.push( parameters.roughnessMapUv );
20988 array.push( parameters.anisotropyMapUv );
20989 array.push( parameters.clearcoatMapUv );
20990 array.push( parameters.clearcoatNormalMapUv );
20991 array.push( parameters.clearcoatRoughnessMapUv );
20992 array.push( parameters.iridescenceMapUv );
20993 array.push( parameters.iridescenceThicknessMapUv );
20994 array.push( parameters.sheenColorMapUv );
20995 array.push( parameters.sheenRoughnessMapUv );
20996 array.push( parameters.specularMapUv );
20997 array.push( parameters.specularColorMapUv );
20998 array.push( parameters.specularIntensityMapUv );
20999 array.push( parameters.transmissionMapUv );
21000 array.push( parameters.thicknessMapUv );
21001 array.push( parameters.combine );
21002 array.push( parameters.fogExp2 );
21003 array.push( parameters.sizeAttenuation );
21004 array.push( parameters.morphTargetsCount );
21005 array.push( parameters.morphAttributeCount );
21006 array.push( parameters.numDirLights );
21007 array.push( parameters.numPointLights );
21008 array.push( parameters.numSpotLights );
21009 array.push( parameters.numSpotLightMaps );
21010 array.push( parameters.numHemiLights );
21011 array.push( parameters.numRectAreaLights );
21012 array.push( parameters.numDirLightShadows );
21013 array.push( parameters.numPointLightShadows );
21014 array.push( parameters.numSpotLightShadows );
21015 array.push( parameters.numSpotLightShadowsWithMaps );
21016 array.push( parameters.numLightProbes );
21017 array.push( parameters.shadowMapType );
21018 array.push( parameters.toneMapping );
21019 array.push( parameters.numClippingPlanes );
21020 array.push( parameters.numClipIntersection );
21021 array.push( parameters.depthPacking );
21022
21023 }
21024
21026
21027 _programLayers.disableAll();
21028
21029 if ( parameters.isWebGL2 )
21030 _programLayers.enable( 0 );
21031 if ( parameters.supportsVertexTextures )
21032 _programLayers.enable( 1 );
21033 if ( parameters.instancing )
21034 _programLayers.enable( 2 );
21035 if ( parameters.instancingColor )
21036 _programLayers.enable( 3 );
21037 if ( parameters.matcap )
21038 _programLayers.enable( 4 );
21039 if ( parameters.envMap )
21040 _programLayers.enable( 5 );
21041 if ( parameters.normalMapObjectSpace )
21042 _programLayers.enable( 6 );
21043 if ( parameters.normalMapTangentSpace )
21044 _programLayers.enable( 7 );
21045 if ( parameters.clearcoat )
21046 _programLayers.enable( 8 );
21047 if ( parameters.iridescence )
21048 _programLayers.enable( 9 );
21049 if ( parameters.alphaTest )
21050 _programLayers.enable( 10 );
21051 if ( parameters.vertexColors )
21052 _programLayers.enable( 11 );
21053 if ( parameters.vertexAlphas )
21054 _programLayers.enable( 12 );
21055 if ( parameters.vertexUv1s )
21056 _programLayers.enable( 13 );
21057 if ( parameters.vertexUv2s )
21058 _programLayers.enable( 14 );
21059 if ( parameters.vertexUv3s )
21060 _programLayers.enable( 15 );
21061 if ( parameters.vertexTangents )
21062 _programLayers.enable( 16 );
21063 if ( parameters.anisotropy )
21064 _programLayers.enable( 17 );
21065 if ( parameters.alphaHash )
21066 _programLayers.enable( 18 );
21067 if ( parameters.batching )
21068 _programLayers.enable( 19 );
21069
21070 array.push( _programLayers.mask );
21071 _programLayers.disableAll();
21072
21073 if ( parameters.fog )
21074 _programLayers.enable( 0 );
21075 if ( parameters.useFog )
21076 _programLayers.enable( 1 );
21077 if ( parameters.flatShading )
21078 _programLayers.enable( 2 );
21079 if ( parameters.logarithmicDepthBuffer )
21080 _programLayers.enable( 3 );
21081 if ( parameters.skinning )
21082 _programLayers.enable( 4 );
21083 if ( parameters.morphTargets )
21084 _programLayers.enable( 5 );
21085 if ( parameters.morphNormals )
21086 _programLayers.enable( 6 );
21087 if ( parameters.morphColors )
21088 _programLayers.enable( 7 );
21089 if ( parameters.premultipliedAlpha )
21090 _programLayers.enable( 8 );
21091 if ( parameters.shadowMapEnabled )
21092 _programLayers.enable( 9 );
21093 if ( parameters.useLegacyLights )
21094 _programLayers.enable( 10 );
21095 if ( parameters.doubleSided )
21096 _programLayers.enable( 11 );
21097 if ( parameters.flipSided )
21098 _programLayers.enable( 12 );
21099 if ( parameters.useDepthPacking )
21100 _programLayers.enable( 13 );
21101 if ( parameters.dithering )
21102 _programLayers.enable( 14 );
21103 if ( parameters.transmission )
21104 _programLayers.enable( 15 );
21105 if ( parameters.sheen )
21106 _programLayers.enable( 16 );
21107 if ( parameters.opaque )
21108 _programLayers.enable( 17 );
21109 if ( parameters.pointsUvs )
21110 _programLayers.enable( 18 );
21111 if ( parameters.decodeVideoTexture )
21112 _programLayers.enable( 19 );
21113
21114 array.push( _programLayers.mask );
21115
21116 }
21117
21118 function getUniforms( material ) {
21119
21120 const shaderID = shaderIDs[ material.type ];
21121 let uniforms;
21122
21123 if ( shaderID ) {
21124
21125 const shader = ShaderLib[ shaderID ];
21126 uniforms = UniformsUtils.clone( shader.uniforms );
21127
21128 } else {
21129
21130 uniforms = material.uniforms;
21131
21132 }
21133
21134 return uniforms;
21135
21136 }
21137
21138 function acquireProgram( parameters, cacheKey ) {
21139
21140 let program;
21141
21142 // Check if code has been already compiled
21143 for ( let p = 0, pl = programs.length; p < pl; p ++ ) {
21144
21145 const preexistingProgram = programs[ p ];
21146
21147 if ( preexistingProgram.cacheKey === cacheKey ) {
21148
21150 ++ program.usedTimes;
21151
21152 break;
21153
21154 }
21155
21156 }
21157
21158 if ( program === undefined ) {
21159
21161 programs.push( program );
21162
21163 }
21164
21165 return program;
21166
21167 }
21168
21169 function releaseProgram( program ) {
21170
21171 if ( -- program.usedTimes === 0 ) {
21172
21173 // Remove from unordered set
21174 const i = programs.indexOf( program );
21175 programs[ i ] = programs[ programs.length - 1 ];
21176 programs.pop();
21177
21178 // Free WebGL resources
21179 program.destroy();
21180
21181 }
21182
21183 }
21184
21185 function releaseShaderCache( material ) {
21186
21187 _customShaders.remove( material );
21188
21189 }
21190
21191 function dispose() {
21192
21193 _customShaders.dispose();
21194
21195 }
21196
21197 return {
21204 // Exposed for resource monitoring & error feedback via renderer.info:
21207 };
21208
21209 }
21210
21211 function WebGLProperties() {
21212
21213 let properties = new WeakMap();
21214
21215 function get( object ) {
21216
21217 let map = properties.get( object );
21218
21219 if ( map === undefined ) {
21220
21221 map = {};
21222 properties.set( object, map );
21223
21224 }
21225
21226 return map;
21227
21228 }
21229
21230 function remove( object ) {
21231
21232 properties.delete( object );
21233
21234 }
21235
21236 function update( object, key, value ) {
21237
21238 properties.get( object )[ key ] = value;
21239
21240 }
21241
21242 function dispose() {
21243
21244 properties = new WeakMap();
21245
21246 }
21247
21248 return {
21249 get: get,
21250 remove: remove,
21251 update: update,
21253 };
21254
21255 }
21256
21257 function painterSortStable( a, b ) {
21258
21259 if ( a.groupOrder !== b.groupOrder ) {
21260
21261 return a.groupOrder - b.groupOrder;
21262
21263 } else if ( a.renderOrder !== b.renderOrder ) {
21264
21265 return a.renderOrder - b.renderOrder;
21266
21267 } else if ( a.material.id !== b.material.id ) {
21268
21269 return a.material.id - b.material.id;
21270
21271 } else if ( a.z !== b.z ) {
21272
21273 return a.z - b.z;
21274
21275 } else {
21276
21277 return a.id - b.id;
21278
21279 }
21280
21281 }
21282
21283 function reversePainterSortStable( a, b ) {
21284
21285 if ( a.groupOrder !== b.groupOrder ) {
21286
21287 return a.groupOrder - b.groupOrder;
21288
21289 } else if ( a.renderOrder !== b.renderOrder ) {
21290
21291 return a.renderOrder - b.renderOrder;
21292
21293 } else if ( a.z !== b.z ) {
21294
21295 return b.z - a.z;
21296
21297 } else {
21298
21299 return a.id - b.id;
21300
21301 }
21302
21303 }
21304
21305
21306 function WebGLRenderList() {
21307
21308 const renderItems = [];
21310
21311 const opaque = [];
21312 const transmissive = [];
21313 const transparent = [];
21314
21315 function init() {
21316
21317 renderItemsIndex = 0;
21318
21319 opaque.length = 0;
21320 transmissive.length = 0;
21321 transparent.length = 0;
21322
21323 }
21324
21325 function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {
21326
21328
21329 if ( renderItem === undefined ) {
21330
21331 renderItem = {
21332 id: object.id,
21333 object: object,
21337 renderOrder: object.renderOrder,
21338 z: z,
21339 group: group
21340 };
21341
21343
21344 } else {
21345
21346 renderItem.id = object.id;
21347 renderItem.object = object;
21348 renderItem.geometry = geometry;
21349 renderItem.material = material;
21350 renderItem.groupOrder = groupOrder;
21351 renderItem.renderOrder = object.renderOrder;
21352 renderItem.z = z;
21353 renderItem.group = group;
21354
21355 }
21356
21358
21359 return renderItem;
21360
21361 }
21362
21363 function push( object, geometry, material, groupOrder, z, group ) {
21364
21366
21367 if ( material.transmission > 0.0 ) {
21368
21369 transmissive.push( renderItem );
21370
21371 } else if ( material.transparent === true ) {
21372
21373 transparent.push( renderItem );
21374
21375 } else {
21376
21377 opaque.push( renderItem );
21378
21379 }
21380
21381 }
21382
21383 function unshift( object, geometry, material, groupOrder, z, group ) {
21384
21386
21387 if ( material.transmission > 0.0 ) {
21388
21389 transmissive.unshift( renderItem );
21390
21391 } else if ( material.transparent === true ) {
21392
21393 transparent.unshift( renderItem );
21394
21395 } else {
21396
21397 opaque.unshift( renderItem );
21398
21399 }
21400
21401 }
21402
21404
21405 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
21408
21409 }
21410
21411 function finish() {
21412
21413 // Clear references from inactive renderItems in the list
21414
21415 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {
21416
21417 const renderItem = renderItems[ i ];
21418
21419 if ( renderItem.id === null ) break;
21420
21421 renderItem.id = null;
21422 renderItem.object = null;
21423 renderItem.geometry = null;
21424 renderItem.material = null;
21425 renderItem.group = null;
21426
21427 }
21428
21429 }
21430
21431 return {
21432
21433 opaque: opaque,
21436
21437 init: init,
21438 push: push,
21440 finish: finish,
21441
21442 sort: sort
21443 };
21444
21445 }
21446
21447 function WebGLRenderLists() {
21448
21449 let lists = new WeakMap();
21450
21451 function get( scene, renderCallDepth ) {
21452
21453 const listArray = lists.get( scene );
21454 let list;
21455
21456 if ( listArray === undefined ) {
21457
21458 list = new WebGLRenderList();
21459 lists.set( scene, [ list ] );
21460
21461 } else {
21462
21463 if ( renderCallDepth >= listArray.length ) {
21464
21465 list = new WebGLRenderList();
21466 listArray.push( list );
21467
21468 } else {
21469
21471
21472 }
21473
21474 }
21475
21476 return list;
21477
21478 }
21479
21480 function dispose() {
21481
21482 lists = new WeakMap();
21483
21484 }
21485
21486 return {
21487 get: get,
21489 };
21490
21491 }
21492
21493 function UniformsCache() {
21494
21495 const lights = {};
21496
21497 return {
21498
21499 get: function ( light ) {
21500
21501 if ( lights[ light.id ] !== undefined ) {
21502
21503 return lights[ light.id ];
21504
21505 }
21506
21507 let uniforms;
21508
21509 switch ( light.type ) {
21510
21511 case 'DirectionalLight':
21512 uniforms = {
21513 direction: new Vector3(),
21514 color: new Color()
21515 };
21516 break;
21517
21518 case 'SpotLight':
21519 uniforms = {
21520 position: new Vector3(),
21521 direction: new Vector3(),
21522 color: new Color(),
21523 distance: 0,
21524 coneCos: 0,
21525 penumbraCos: 0,
21526 decay: 0
21527 };
21528 break;
21529
21530 case 'PointLight':
21531 uniforms = {
21532 position: new Vector3(),
21533 color: new Color(),
21534 distance: 0,
21535 decay: 0
21536 };
21537 break;
21538
21539 case 'HemisphereLight':
21540 uniforms = {
21541 direction: new Vector3(),
21542 skyColor: new Color(),
21543 groundColor: new Color()
21544 };
21545 break;
21546
21547 case 'RectAreaLight':
21548 uniforms = {
21549 color: new Color(),
21550 position: new Vector3(),
21551 halfWidth: new Vector3(),
21552 halfHeight: new Vector3()
21553 };
21554 break;
21555
21556 }
21557
21558 lights[ light.id ] = uniforms;
21559
21560 return uniforms;
21561
21562 }
21563
21564 };
21565
21566 }
21567
21568 function ShadowUniformsCache() {
21569
21570 const lights = {};
21571
21572 return {
21573
21574 get: function ( light ) {
21575
21576 if ( lights[ light.id ] !== undefined ) {
21577
21578 return lights[ light.id ];
21579
21580 }
21581
21582 let uniforms;
21583
21584 switch ( light.type ) {
21585
21586 case 'DirectionalLight':
21587 uniforms = {
21588 shadowBias: 0,
21590 shadowRadius: 1,
21591 shadowMapSize: new Vector2()
21592 };
21593 break;
21594
21595 case 'SpotLight':
21596 uniforms = {
21597 shadowBias: 0,
21599 shadowRadius: 1,
21600 shadowMapSize: new Vector2()
21601 };
21602 break;
21603
21604 case 'PointLight':
21605 uniforms = {
21606 shadowBias: 0,
21608 shadowRadius: 1,
21609 shadowMapSize: new Vector2(),
21611 shadowCameraFar: 1000
21612 };
21613 break;
21614
21615 // TODO (abelnation): set RectAreaLight shadow uniforms
21616
21617 }
21618
21619 lights[ light.id ] = uniforms;
21620
21621 return uniforms;
21622
21623 }
21624
21625 };
21626
21627 }
21628
21629
21630
21631 let nextVersion = 0;
21632
21634
21635 return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );
21636
21637 }
21638
21639 function WebGLLights( extensions, capabilities ) {
21640
21641 const cache = new UniformsCache();
21642
21644
21645 const state = {
21646
21647 version: 0,
21648
21649 hash: {
21650 directionalLength: - 1,
21651 pointLength: - 1,
21652 spotLength: - 1,
21653 rectAreaLength: - 1,
21654 hemiLength: - 1,
21655
21657 numPointShadows: - 1,
21658 numSpotShadows: - 1,
21659 numSpotMaps: - 1,
21660
21661 numLightProbes: - 1
21662 },
21663
21664 ambient: [ 0, 0, 0 ],
21665 probe: [],
21666 directional: [],
21670 spot: [],
21671 spotLightMap: [],
21672 spotShadow: [],
21673 spotShadowMap: [],
21674 spotLightMatrix: [],
21675 rectArea: [],
21676 rectAreaLTC1: null,
21677 rectAreaLTC2: null,
21678 point: [],
21679 pointShadow: [],
21680 pointShadowMap: [],
21682 hemi: [],
21685
21686 };
21687
21688 for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );
21689
21690 const vector3 = new Vector3();
21691 const matrix4 = new Matrix4();
21692 const matrix42 = new Matrix4();
21693
21694 function setup( lights, useLegacyLights ) {
21695
21696 let r = 0, g = 0, b = 0;
21697
21698 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );
21699
21701 let pointLength = 0;
21702 let spotLength = 0;
21703 let rectAreaLength = 0;
21704 let hemiLength = 0;
21705
21707 let numPointShadows = 0;
21708 let numSpotShadows = 0;
21709 let numSpotMaps = 0;
21711
21712 let numLightProbes = 0;
21713
21714 // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
21716
21717 // artist-friendly light intensity scaling factor
21718 const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1;
21719
21720 for ( let i = 0, l = lights.length; i < l; i ++ ) {
21721
21722 const light = lights[ i ];
21723
21724 const color = light.color;
21725 const intensity = light.intensity;
21726 const distance = light.distance;
21727
21728 const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
21729
21730 if ( light.isAmbientLight ) {
21731
21732 r += color.r * intensity * scaleFactor;
21733 g += color.g * intensity * scaleFactor;
21734 b += color.b * intensity * scaleFactor;
21735
21736 } else if ( light.isLightProbe ) {
21737
21738 for ( let j = 0; j < 9; j ++ ) {
21739
21740 state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );
21741
21742 }
21743
21744 numLightProbes ++;
21745
21746 } else if ( light.isDirectionalLight ) {
21747
21748 const uniforms = cache.get( light );
21749
21750 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21751
21752 if ( light.castShadow ) {
21753
21754 const shadow = light.shadow;
21755
21756 const shadowUniforms = shadowCache.get( light );
21757
21758 shadowUniforms.shadowBias = shadow.bias;
21759 shadowUniforms.shadowNormalBias = shadow.normalBias;
21760 shadowUniforms.shadowRadius = shadow.radius;
21761 shadowUniforms.shadowMapSize = shadow.mapSize;
21762
21763 state.directionalShadow[ directionalLength ] = shadowUniforms;
21764 state.directionalShadowMap[ directionalLength ] = shadowMap;
21765 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
21766
21768
21769 }
21770
21771 state.directional[ directionalLength ] = uniforms;
21772
21774
21775 } else if ( light.isSpotLight ) {
21776
21777 const uniforms = cache.get( light );
21778
21779 uniforms.position.setFromMatrixPosition( light.matrixWorld );
21780
21781 uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor );
21782 uniforms.distance = distance;
21783
21784 uniforms.coneCos = Math.cos( light.angle );
21785 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
21786 uniforms.decay = light.decay;
21787
21788 state.spot[ spotLength ] = uniforms;
21789
21790 const shadow = light.shadow;
21791
21792 if ( light.map ) {
21793
21794 state.spotLightMap[ numSpotMaps ] = light.map;
21795 numSpotMaps ++;
21796
21797 // make sure the lightMatrix is up to date
21798 // TODO : do it if required only
21799 shadow.updateMatrices( light );
21800
21801 if ( light.castShadow ) numSpotShadowsWithMaps ++;
21802
21803 }
21804
21805 state.spotLightMatrix[ spotLength ] = shadow.matrix;
21806
21807 if ( light.castShadow ) {
21808
21809 const shadowUniforms = shadowCache.get( light );
21810
21811 shadowUniforms.shadowBias = shadow.bias;
21812 shadowUniforms.shadowNormalBias = shadow.normalBias;
21813 shadowUniforms.shadowRadius = shadow.radius;
21814 shadowUniforms.shadowMapSize = shadow.mapSize;
21815
21816 state.spotShadow[ spotLength ] = shadowUniforms;
21817 state.spotShadowMap[ spotLength ] = shadowMap;
21818
21819 numSpotShadows ++;
21820
21821 }
21822
21823 spotLength ++;
21824
21825 } else if ( light.isRectAreaLight ) {
21826
21827 const uniforms = cache.get( light );
21828
21829 uniforms.color.copy( color ).multiplyScalar( intensity );
21830
21831 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
21832 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
21833
21834 state.rectArea[ rectAreaLength ] = uniforms;
21835
21836 rectAreaLength ++;
21837
21838 } else if ( light.isPointLight ) {
21839
21840 const uniforms = cache.get( light );
21841
21842 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor );
21843 uniforms.distance = light.distance;
21844 uniforms.decay = light.decay;
21845
21846 if ( light.castShadow ) {
21847
21848 const shadow = light.shadow;
21849
21850 const shadowUniforms = shadowCache.get( light );
21851
21852 shadowUniforms.shadowBias = shadow.bias;
21853 shadowUniforms.shadowNormalBias = shadow.normalBias;
21854 shadowUniforms.shadowRadius = shadow.radius;
21855 shadowUniforms.shadowMapSize = shadow.mapSize;
21856 shadowUniforms.shadowCameraNear = shadow.camera.near;
21857 shadowUniforms.shadowCameraFar = shadow.camera.far;
21858
21859 state.pointShadow[ pointLength ] = shadowUniforms;
21860 state.pointShadowMap[ pointLength ] = shadowMap;
21861 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
21862
21863 numPointShadows ++;
21864
21865 }
21866
21867 state.point[ pointLength ] = uniforms;
21868
21869 pointLength ++;
21870
21871 } else if ( light.isHemisphereLight ) {
21872
21873 const uniforms = cache.get( light );
21874
21875 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor );
21876 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor );
21877
21878 state.hemi[ hemiLength ] = uniforms;
21879
21880 hemiLength ++;
21881
21882 }
21883
21884 }
21885
21886 if ( rectAreaLength > 0 ) {
21887
21888 if ( capabilities.isWebGL2 ) {
21889
21890 // WebGL 2
21891
21892 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21893
21894 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21895 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21896
21897 } else {
21898
21899 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21900 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21901
21902 }
21903
21904 } else {
21905
21906 // WebGL 1
21907
21908 if ( extensions.has( 'OES_texture_float_linear' ) === true ) {
21909
21910 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
21911 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
21912
21913 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) {
21914
21915 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
21916 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
21917
21918 } else {
21919
21920 console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' );
21921
21922 }
21923
21924 }
21925
21926 }
21927
21928 state.ambient[ 0 ] = r;
21929 state.ambient[ 1 ] = g;
21930 state.ambient[ 2 ] = b;
21931
21932 const hash = state.hash;
21933
21934 if ( hash.directionalLength !== directionalLength ||
21935 hash.pointLength !== pointLength ||
21936 hash.spotLength !== spotLength ||
21937 hash.rectAreaLength !== rectAreaLength ||
21938 hash.hemiLength !== hemiLength ||
21939 hash.numDirectionalShadows !== numDirectionalShadows ||
21940 hash.numPointShadows !== numPointShadows ||
21941 hash.numSpotShadows !== numSpotShadows ||
21942 hash.numSpotMaps !== numSpotMaps ||
21943 hash.numLightProbes !== numLightProbes ) {
21944
21945 state.directional.length = directionalLength;
21946 state.spot.length = spotLength;
21947 state.rectArea.length = rectAreaLength;
21948 state.point.length = pointLength;
21949 state.hemi.length = hemiLength;
21950
21951 state.directionalShadow.length = numDirectionalShadows;
21952 state.directionalShadowMap.length = numDirectionalShadows;
21953 state.pointShadow.length = numPointShadows;
21954 state.pointShadowMap.length = numPointShadows;
21955 state.spotShadow.length = numSpotShadows;
21956 state.spotShadowMap.length = numSpotShadows;
21957 state.directionalShadowMatrix.length = numDirectionalShadows;
21958 state.pointShadowMatrix.length = numPointShadows;
21959 state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
21960 state.spotLightMap.length = numSpotMaps;
21961 state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
21962 state.numLightProbes = numLightProbes;
21963
21964 hash.directionalLength = directionalLength;
21965 hash.pointLength = pointLength;
21966 hash.spotLength = spotLength;
21967 hash.rectAreaLength = rectAreaLength;
21968 hash.hemiLength = hemiLength;
21969
21970 hash.numDirectionalShadows = numDirectionalShadows;
21971 hash.numPointShadows = numPointShadows;
21972 hash.numSpotShadows = numSpotShadows;
21973 hash.numSpotMaps = numSpotMaps;
21974
21975 hash.numLightProbes = numLightProbes;
21976
21977 state.version = nextVersion ++;
21978
21979 }
21980
21981 }
21982
21983 function setupView( lights, camera ) {
21984
21986 let pointLength = 0;
21987 let spotLength = 0;
21988 let rectAreaLength = 0;
21989 let hemiLength = 0;
21990
21991 const viewMatrix = camera.matrixWorldInverse;
21992
21993 for ( let i = 0, l = lights.length; i < l; i ++ ) {
21994
21995 const light = lights[ i ];
21996
21997 if ( light.isDirectionalLight ) {
21998
21999 const uniforms = state.directional[ directionalLength ];
22000
22001 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22002 vector3.setFromMatrixPosition( light.target.matrixWorld );
22003 uniforms.direction.sub( vector3 );
22004 uniforms.direction.transformDirection( viewMatrix );
22005
22007
22008 } else if ( light.isSpotLight ) {
22009
22010 const uniforms = state.spot[ spotLength ];
22011
22012 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22013 uniforms.position.applyMatrix4( viewMatrix );
22014
22015 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22016 vector3.setFromMatrixPosition( light.target.matrixWorld );
22017 uniforms.direction.sub( vector3 );
22018 uniforms.direction.transformDirection( viewMatrix );
22019
22020 spotLength ++;
22021
22022 } else if ( light.isRectAreaLight ) {
22023
22024 const uniforms = state.rectArea[ rectAreaLength ];
22025
22026 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22027 uniforms.position.applyMatrix4( viewMatrix );
22028
22029 // extract local rotation of light to derive width/height half vectors
22030 matrix42.identity();
22031 matrix4.copy( light.matrixWorld );
22032 matrix4.premultiply( viewMatrix );
22033 matrix42.extractRotation( matrix4 );
22034
22035 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
22036 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
22037
22038 uniforms.halfWidth.applyMatrix4( matrix42 );
22039 uniforms.halfHeight.applyMatrix4( matrix42 );
22040
22041 rectAreaLength ++;
22042
22043 } else if ( light.isPointLight ) {
22044
22045 const uniforms = state.point[ pointLength ];
22046
22047 uniforms.position.setFromMatrixPosition( light.matrixWorld );
22048 uniforms.position.applyMatrix4( viewMatrix );
22049
22050 pointLength ++;
22051
22052 } else if ( light.isHemisphereLight ) {
22053
22054 const uniforms = state.hemi[ hemiLength ];
22055
22056 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
22057 uniforms.direction.transformDirection( viewMatrix );
22058
22059 hemiLength ++;
22060
22061 }
22062
22063 }
22064
22065 }
22066
22067 return {
22068 setup: setup,
22070 state: state
22071 };
22072
22073 }
22074
22076
22077 const lights = new WebGLLights( extensions, capabilities );
22078
22079 const lightsArray = [];
22080 const shadowsArray = [];
22081
22082 function init() {
22083
22084 lightsArray.length = 0;
22085 shadowsArray.length = 0;
22086
22087 }
22088
22089 function pushLight( light ) {
22090
22091 lightsArray.push( light );
22092
22093 }
22094
22095 function pushShadow( shadowLight ) {
22096
22097 shadowsArray.push( shadowLight );
22098
22099 }
22100
22101 function setupLights( useLegacyLights ) {
22102
22104
22105 }
22106
22107 function setupLightsView( camera ) {
22108
22109 lights.setupView( lightsArray, camera );
22110
22111 }
22112
22113 const state = {
22116
22117 lights: lights
22118 };
22119
22120 return {
22121 init: init,
22122 state: state,
22125
22128 };
22129
22130 }
22131
22133
22134 let renderStates = new WeakMap();
22135
22136 function get( scene, renderCallDepth = 0 ) {
22137
22138 const renderStateArray = renderStates.get( scene );
22140
22141 if ( renderStateArray === undefined ) {
22142
22144 renderStates.set( scene, [ renderState ] );
22145
22146 } else {
22147
22148 if ( renderCallDepth >= renderStateArray.length ) {
22149
22152
22153 } else {
22154
22156
22157 }
22158
22159 }
22160
22161 return renderState;
22162
22163 }
22164
22165 function dispose() {
22166
22167 renderStates = new WeakMap();
22168
22169 }
22170
22171 return {
22172 get: get,
22174 };
22175
22176 }
22177
22178 class MeshDepthMaterial extends Material {
22179
22181
22182 super();
22183
22184 this.isMeshDepthMaterial = true;
22185
22186 this.type = 'MeshDepthMaterial';
22187
22189
22190 this.map = null;
22191
22192 this.alphaMap = null;
22193
22194 this.displacementMap = null;
22195 this.displacementScale = 1;
22196 this.displacementBias = 0;
22197
22198 this.wireframe = false;
22199 this.wireframeLinewidth = 1;
22200
22201 this.setValues( parameters );
22202
22203 }
22204
22205 copy( source ) {
22206
22207 super.copy( source );
22208
22209 this.depthPacking = source.depthPacking;
22210
22211 this.map = source.map;
22212
22213 this.alphaMap = source.alphaMap;
22214
22215 this.displacementMap = source.displacementMap;
22216 this.displacementScale = source.displacementScale;
22217 this.displacementBias = source.displacementBias;
22218
22219 this.wireframe = source.wireframe;
22220 this.wireframeLinewidth = source.wireframeLinewidth;
22221
22222 return this;
22223
22224 }
22225
22226 }
22227
22228 class MeshDistanceMaterial extends Material {
22229
22230 constructor( parameters ) {
22231
22232 super();
22233
22234 this.isMeshDistanceMaterial = true;
22235
22236 this.type = 'MeshDistanceMaterial';
22237
22238 this.map = null;
22239
22240 this.alphaMap = null;
22241
22242 this.displacementMap = null;
22243 this.displacementScale = 1;
22244 this.displacementBias = 0;
22245
22246 this.setValues( parameters );
22247
22248 }
22249
22250 copy( source ) {
22251
22252 super.copy( source );
22253
22254 this.map = source.map;
22255
22256 this.alphaMap = source.alphaMap;
22257
22258 this.displacementMap = source.displacementMap;
22259 this.displacementScale = source.displacementScale;
22260 this.displacementBias = source.displacementBias;
22261
22262 return this;
22263
22264 }
22265
22266 }
22267
22268 const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}";
22269
22270 const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}";
22271
22273
22274 let _frustum = new Frustum();
22275
22276 const _shadowMapSize = new Vector2(),
22277 _viewportSize = new Vector2(),
22278
22279 _viewport = new Vector4(),
22280
22283
22284 _materialCache = {},
22285
22286 _maxTextureSize = _capabilities.maxTextureSize;
22287
22289
22291 defines: {
22292 VSM_SAMPLES: 8
22293 },
22294 uniforms: {
22295 shadow_pass: { value: null },
22296 resolution: { value: new Vector2() },
22297 radius: { value: 4.0 }
22298 },
22299
22302
22303 } );
22304
22306 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
22307
22308 const fullScreenTri = new BufferGeometry();
22309 fullScreenTri.setAttribute(
22310 'position',
22311 new BufferAttribute(
22312 new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),
22313 3
22314 )
22315 );
22316
22318
22319 const scope = this;
22320
22321 this.enabled = false;
22322
22323 this.autoUpdate = true;
22324 this.needsUpdate = false;
22325
22326 this.type = PCFShadowMap;
22327 let _previousType = this.type;
22328
22329 this.render = function ( lights, scene, camera ) {
22330
22331 if ( scope.enabled === false ) return;
22332 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
22333
22334 if ( lights.length === 0 ) return;
22335
22336 const currentRenderTarget = _renderer.getRenderTarget();
22337 const activeCubeFace = _renderer.getActiveCubeFace();
22338 const activeMipmapLevel = _renderer.getActiveMipmapLevel();
22339
22340 const _state = _renderer.state;
22341
22342 // Set GL state for depth map.
22343 _state.setBlending( NoBlending );
22344 _state.buffers.color.setClear( 1, 1, 1, 1 );
22345 _state.buffers.depth.setTest( true );
22346 _state.setScissorTest( false );
22347
22348 // check for shadow map type changes
22349
22350 const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap );
22351 const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap );
22352
22353 // render depth map
22354
22355 for ( let i = 0, il = lights.length; i < il; i ++ ) {
22356
22357 const light = lights[ i ];
22358 const shadow = light.shadow;
22359
22360 if ( shadow === undefined ) {
22361
22362 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
22363 continue;
22364
22365 }
22366
22367 if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;
22368
22369 _shadowMapSize.copy( shadow.mapSize );
22370
22371 const shadowFrameExtents = shadow.getFrameExtents();
22372
22374
22375 _viewportSize.copy( shadow.mapSize );
22376
22378
22379 if ( _shadowMapSize.x > _maxTextureSize ) {
22380
22383 shadow.mapSize.x = _viewportSize.x;
22384
22385 }
22386
22387 if ( _shadowMapSize.y > _maxTextureSize ) {
22388
22391 shadow.mapSize.y = _viewportSize.y;
22392
22393 }
22394
22395 }
22396
22397 if ( shadow.map === null || toVSM === true || fromVSM === true ) {
22398
22399 const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {};
22400
22401 if ( shadow.map !== null ) {
22402
22403 shadow.map.dispose();
22404
22405 }
22406
22408 shadow.map.texture.name = light.name + '.shadowMap';
22409
22410 shadow.camera.updateProjectionMatrix();
22411
22412 }
22413
22414 _renderer.setRenderTarget( shadow.map );
22415 _renderer.clear();
22416
22417 const viewportCount = shadow.getViewportCount();
22418
22419 for ( let vp = 0; vp < viewportCount; vp ++ ) {
22420
22421 const viewport = shadow.getViewport( vp );
22422
22423 _viewport.set(
22424 _viewportSize.x * viewport.x,
22425 _viewportSize.y * viewport.y,
22426 _viewportSize.x * viewport.z,
22428 );
22429
22430 _state.viewport( _viewport );
22431
22432 shadow.updateMatrices( light, vp );
22433
22434 _frustum = shadow.getFrustum();
22435
22436 renderObject( scene, camera, shadow.camera, light, this.type );
22437
22438 }
22439
22440 // do blur pass for VSM
22441
22442 if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {
22443
22444 VSMPass( shadow, camera );
22445
22446 }
22447
22448 shadow.needsUpdate = false;
22449
22450 }
22451
22452 _previousType = this.type;
22453
22454 scope.needsUpdate = false;
22455
22457
22458 };
22459
22460 function VSMPass( shadow, camera ) {
22461
22462 const geometry = _objects.update( fullScreenMesh );
22463
22464 if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {
22465
22466 shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
22467 shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;
22468
22469 shadowMaterialVertical.needsUpdate = true;
22470 shadowMaterialHorizontal.needsUpdate = true;
22471
22472 }
22473
22474 if ( shadow.mapPass === null ) {
22475
22477
22478 }
22479
22480 // vertical pass
22481
22482 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
22483 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
22484 shadowMaterialVertical.uniforms.radius.value = shadow.radius;
22485 _renderer.setRenderTarget( shadow.mapPass );
22486 _renderer.clear();
22487 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );
22488
22489 // horizontal pass
22490
22491 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
22492 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
22493 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
22494 _renderer.setRenderTarget( shadow.map );
22495 _renderer.clear();
22496 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );
22497
22498 }
22499
22500 function getDepthMaterial( object, material, light, type ) {
22501
22502 let result = null;
22503
22504 const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;
22505
22506 if ( customMaterial !== undefined ) {
22507
22509
22510 } else {
22511
22512 result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;
22513
22514 if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) ||
22515 ( material.displacementMap && material.displacementScale !== 0 ) ||
22516 ( material.alphaMap && material.alphaTest > 0 ) ||
22517 ( material.map && material.alphaTest > 0 ) ) {
22518
22519 // in this case we need a unique material instance reflecting the
22520 // appropriate state
22521
22522 const keyA = result.uuid, keyB = material.uuid;
22523
22525
22526 if ( materialsForVariant === undefined ) {
22527
22530
22531 }
22532
22534
22535 if ( cachedMaterial === undefined ) {
22536
22537 cachedMaterial = result.clone();
22539 material.addEventListener( 'dispose', onMaterialDispose );
22540
22541 }
22542
22544
22545 }
22546
22547 }
22548
22549 result.visible = material.visible;
22550 result.wireframe = material.wireframe;
22551
22552 if ( type === VSMShadowMap ) {
22553
22554 result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;
22555
22556 } else {
22557
22558 result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];
22559
22560 }
22561
22562 result.alphaMap = material.alphaMap;
22563 result.alphaTest = material.alphaTest;
22564 result.map = material.map;
22565
22566 result.clipShadows = material.clipShadows;
22567 result.clippingPlanes = material.clippingPlanes;
22568 result.clipIntersection = material.clipIntersection;
22569
22570 result.displacementMap = material.displacementMap;
22571 result.displacementScale = material.displacementScale;
22572 result.displacementBias = material.displacementBias;
22573
22574 result.wireframeLinewidth = material.wireframeLinewidth;
22575 result.linewidth = material.linewidth;
22576
22577 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {
22578
22579 const materialProperties = _renderer.properties.get( result );
22580 materialProperties.light = light;
22581
22582 }
22583
22584 return result;
22585
22586 }
22587
22588 function renderObject( object, camera, shadowCamera, light, type ) {
22589
22590 if ( object.visible === false ) return;
22591
22592 const visible = object.layers.test( camera.layers );
22593
22594 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
22595
22596 if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
22597
22598 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
22599
22600 const geometry = _objects.update( object );
22601 const material = object.material;
22602
22603 if ( Array.isArray( material ) ) {
22604
22605 const groups = geometry.groups;
22606
22607 for ( let k = 0, kl = groups.length; k < kl; k ++ ) {
22608
22609 const group = groups[ k ];
22610 const groupMaterial = material[ group.materialIndex ];
22611
22612 if ( groupMaterial && groupMaterial.visible ) {
22613
22614 const depthMaterial = getDepthMaterial( object, groupMaterial, light, type );
22615
22616 object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22617
22618 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
22619
22620 object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group );
22621
22622 }
22623
22624 }
22625
22626 } else if ( material.visible ) {
22627
22628 const depthMaterial = getDepthMaterial( object, material, light, type );
22629
22630 object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22631
22632 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
22633
22634 object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null );
22635
22636 }
22637
22638 }
22639
22640 }
22641
22642 const children = object.children;
22643
22644 for ( let i = 0, l = children.length; i < l; i ++ ) {
22645
22647
22648 }
22649
22650 }
22651
22652 function onMaterialDispose( event ) {
22653
22654 const material = event.target;
22655
22656 material.removeEventListener( 'dispose', onMaterialDispose );
22657
22658 // make sure to remove the unique distance/depth materials used for shadow map rendering
22659
22660 for ( const id in _materialCache ) {
22661
22662 const cache = _materialCache[ id ];
22663
22664 const uuid = event.target.uuid;
22665
22666 if ( uuid in cache ) {
22667
22668 const shadowMaterial = cache[ uuid ];
22669 shadowMaterial.dispose();
22670 delete cache[ uuid ];
22671
22672 }
22673
22674 }
22675
22676 }
22677
22678 }
22679
22680 function WebGLState( gl, extensions, capabilities ) {
22681
22682 const isWebGL2 = capabilities.isWebGL2;
22683
22684 function ColorBuffer() {
22685
22686 let locked = false;
22687
22688 const color = new Vector4();
22689 let currentColorMask = null;
22690 const currentColorClear = new Vector4( 0, 0, 0, 0 );
22691
22692 return {
22693
22694 setMask: function ( colorMask ) {
22695
22696 if ( currentColorMask !== colorMask && ! locked ) {
22697
22698 gl.colorMask( colorMask, colorMask, colorMask, colorMask );
22700
22701 }
22702
22703 },
22704
22705 setLocked: function ( lock ) {
22706
22707 locked = lock;
22708
22709 },
22710
22711 setClear: function ( r, g, b, a, premultipliedAlpha ) {
22712
22713 if ( premultipliedAlpha === true ) {
22714
22715 r *= a; g *= a; b *= a;
22716
22717 }
22718
22719 color.set( r, g, b, a );
22720
22721 if ( currentColorClear.equals( color ) === false ) {
22722
22723 gl.clearColor( r, g, b, a );
22724 currentColorClear.copy( color );
22725
22726 }
22727
22728 },
22729
22730 reset: function () {
22731
22732 locked = false;
22733
22734 currentColorMask = null;
22735 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
22736
22737 }
22738
22739 };
22740
22741 }
22742
22743 function DepthBuffer() {
22744
22745 let locked = false;
22746
22747 let currentDepthMask = null;
22748 let currentDepthFunc = null;
22749 let currentDepthClear = null;
22750
22751 return {
22752
22753 setTest: function ( depthTest ) {
22754
22755 if ( depthTest ) {
22756
22757 enable( gl.DEPTH_TEST );
22758
22759 } else {
22760
22761 disable( gl.DEPTH_TEST );
22762
22763 }
22764
22765 },
22766
22767 setMask: function ( depthMask ) {
22768
22769 if ( currentDepthMask !== depthMask && ! locked ) {
22770
22771 gl.depthMask( depthMask );
22773
22774 }
22775
22776 },
22777
22778 setFunc: function ( depthFunc ) {
22779
22780 if ( currentDepthFunc !== depthFunc ) {
22781
22782 switch ( depthFunc ) {
22783
22784 case NeverDepth:
22785
22786 gl.depthFunc( gl.NEVER );
22787 break;
22788
22789 case AlwaysDepth:
22790
22791 gl.depthFunc( gl.ALWAYS );
22792 break;
22793
22794 case LessDepth:
22795
22796 gl.depthFunc( gl.LESS );
22797 break;
22798
22799 case LessEqualDepth:
22800
22801 gl.depthFunc( gl.LEQUAL );
22802 break;
22803
22804 case EqualDepth:
22805
22806 gl.depthFunc( gl.EQUAL );
22807 break;
22808
22809 case GreaterEqualDepth:
22810
22811 gl.depthFunc( gl.GEQUAL );
22812 break;
22813
22814 case GreaterDepth:
22815
22816 gl.depthFunc( gl.GREATER );
22817 break;
22818
22819 case NotEqualDepth:
22820
22821 gl.depthFunc( gl.NOTEQUAL );
22822 break;
22823
22824 default:
22825
22826 gl.depthFunc( gl.LEQUAL );
22827
22828 }
22829
22831
22832 }
22833
22834 },
22835
22836 setLocked: function ( lock ) {
22837
22838 locked = lock;
22839
22840 },
22841
22842 setClear: function ( depth ) {
22843
22844 if ( currentDepthClear !== depth ) {
22845
22846 gl.clearDepth( depth );
22848
22849 }
22850
22851 },
22852
22853 reset: function () {
22854
22855 locked = false;
22856
22857 currentDepthMask = null;
22858 currentDepthFunc = null;
22859 currentDepthClear = null;
22860
22861 }
22862
22863 };
22864
22865 }
22866
22867 function StencilBuffer() {
22868
22869 let locked = false;
22870
22871 let currentStencilMask = null;
22872 let currentStencilFunc = null;
22873 let currentStencilRef = null;
22875 let currentStencilFail = null;
22876 let currentStencilZFail = null;
22877 let currentStencilZPass = null;
22878 let currentStencilClear = null;
22879
22880 return {
22881
22882 setTest: function ( stencilTest ) {
22883
22884 if ( ! locked ) {
22885
22886 if ( stencilTest ) {
22887
22888 enable( gl.STENCIL_TEST );
22889
22890 } else {
22891
22892 disable( gl.STENCIL_TEST );
22893
22894 }
22895
22896 }
22897
22898 },
22899
22900 setMask: function ( stencilMask ) {
22901
22902 if ( currentStencilMask !== stencilMask && ! locked ) {
22903
22904 gl.stencilMask( stencilMask );
22906
22907 }
22908
22909 },
22910
22911 setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
22912
22916
22917 gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
22918
22922
22923 }
22924
22925 },
22926
22927 setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
22928
22932
22933 gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
22934
22938
22939 }
22940
22941 },
22942
22943 setLocked: function ( lock ) {
22944
22945 locked = lock;
22946
22947 },
22948
22949 setClear: function ( stencil ) {
22950
22951 if ( currentStencilClear !== stencil ) {
22952
22953 gl.clearStencil( stencil );
22955
22956 }
22957
22958 },
22959
22960 reset: function () {
22961
22962 locked = false;
22963
22964 currentStencilMask = null;
22965 currentStencilFunc = null;
22966 currentStencilRef = null;
22968 currentStencilFail = null;
22969 currentStencilZFail = null;
22970 currentStencilZPass = null;
22971 currentStencilClear = null;
22972
22973 }
22974
22975 };
22976
22977 }
22978
22979 //
22980
22981 const colorBuffer = new ColorBuffer();
22982 const depthBuffer = new DepthBuffer();
22983 const stencilBuffer = new StencilBuffer();
22984
22985 const uboBindings = new WeakMap();
22986 const uboProgramMap = new WeakMap();
22987
22989
22993
22994 let currentProgram = null;
22995
22997 let currentBlending = null;
22999 let currentBlendSrc = null;
23000 let currentBlendDst = null;
23004 let currentBlendColor = new Color( 0, 0, 0 );
23007
23008 let currentFlipSided = null;
23009 let currentCullFace = null;
23010
23011 let currentLineWidth = null;
23012
23015
23016 const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
23017
23018 let lineWidthAvailable = false;
23019 let version = 0;
23020 const glVersion = gl.getParameter( gl.VERSION );
23021
23022 if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {
23023
23024 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
23025 lineWidthAvailable = ( version >= 1.0 );
23026
23027 } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {
23028
23029 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
23030 lineWidthAvailable = ( version >= 2.0 );
23031
23032 }
23033
23034 let currentTextureSlot = null;
23036
23037 const scissorParam = gl.getParameter( gl.SCISSOR_BOX );
23038 const viewportParam = gl.getParameter( gl.VIEWPORT );
23039
23040 const currentScissor = new Vector4().fromArray( scissorParam );
23041 const currentViewport = new Vector4().fromArray( viewportParam );
23042
23043 function createTexture( type, target, count, dimensions ) {
23044
23045 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
23046 const texture = gl.createTexture();
23047
23048 gl.bindTexture( type, texture );
23049 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
23050 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
23051
23052 for ( let i = 0; i < count; i ++ ) {
23053
23054 if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) {
23055
23056 gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23057
23058 } else {
23059
23060 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
23061
23062 }
23063
23064 }
23065
23066 return texture;
23067
23068 }
23069
23070 const emptyTextures = {};
23071 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
23072 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
23073
23074 if ( isWebGL2 ) {
23075
23076 emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );
23077 emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );
23078
23079 }
23080
23081 // init
23082
23083 colorBuffer.setClear( 0, 0, 0, 1 );
23084 depthBuffer.setClear( 1 );
23085 stencilBuffer.setClear( 0 );
23086
23087 enable( gl.DEPTH_TEST );
23088 depthBuffer.setFunc( LessEqualDepth );
23089
23090 setFlipSided( false );
23092 enable( gl.CULL_FACE );
23093
23095
23096 //
23097
23098 function enable( id ) {
23099
23100 if ( enabledCapabilities[ id ] !== true ) {
23101
23102 gl.enable( id );
23103 enabledCapabilities[ id ] = true;
23104
23105 }
23106
23107 }
23108
23109 function disable( id ) {
23110
23111 if ( enabledCapabilities[ id ] !== false ) {
23112
23113 gl.disable( id );
23114 enabledCapabilities[ id ] = false;
23115
23116 }
23117
23118 }
23119
23120 function bindFramebuffer( target, framebuffer ) {
23121
23123
23124 gl.bindFramebuffer( target, framebuffer );
23125
23127
23128 if ( isWebGL2 ) {
23129
23130 // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
23131
23132 if ( target === gl.DRAW_FRAMEBUFFER ) {
23133
23134 currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;
23135
23136 }
23137
23138 if ( target === gl.FRAMEBUFFER ) {
23139
23140 currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;
23141
23142 }
23143
23144 }
23145
23146 return true;
23147
23148 }
23149
23150 return false;
23151
23152 }
23153
23154 function drawBuffers( renderTarget, framebuffer ) {
23155
23157
23158 let needsUpdate = false;
23159
23160 if ( renderTarget ) {
23161
23163
23164 if ( drawBuffers === undefined ) {
23165
23166 drawBuffers = [];
23168
23169 }
23170
23171 if ( renderTarget.isWebGLMultipleRenderTargets ) {
23172
23173 const textures = renderTarget.texture;
23174
23175 if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23176
23177 for ( let i = 0, il = textures.length; i < il; i ++ ) {
23178
23179 drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
23180
23181 }
23182
23183 drawBuffers.length = textures.length;
23184
23185 needsUpdate = true;
23186
23187 }
23188
23189 } else {
23190
23191 if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {
23192
23193 drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0;
23194
23195 needsUpdate = true;
23196
23197 }
23198
23199 }
23200
23201 } else {
23202
23203 if ( drawBuffers[ 0 ] !== gl.BACK ) {
23204
23205 drawBuffers[ 0 ] = gl.BACK;
23206
23207 needsUpdate = true;
23208
23209 }
23210
23211 }
23212
23213 if ( needsUpdate ) {
23214
23215 if ( capabilities.isWebGL2 ) {
23216
23217 gl.drawBuffers( drawBuffers );
23218
23219 } else {
23220
23221 extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers );
23222
23223 }
23224
23225 }
23226
23227
23228 }
23229
23230 function useProgram( program ) {
23231
23232 if ( currentProgram !== program ) {
23233
23234 gl.useProgram( program );
23235
23237
23238 return true;
23239
23240 }
23241
23242 return false;
23243
23244 }
23245
23246 const equationToGL = {
23247 [ AddEquation ]: gl.FUNC_ADD,
23248 [ SubtractEquation ]: gl.FUNC_SUBTRACT,
23249 [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
23250 };
23251
23252 if ( isWebGL2 ) {
23253
23254 equationToGL[ MinEquation ] = gl.MIN;
23255 equationToGL[ MaxEquation ] = gl.MAX;
23256
23257 } else {
23258
23259 const extension = extensions.get( 'EXT_blend_minmax' );
23260
23261 if ( extension !== null ) {
23262
23263 equationToGL[ MinEquation ] = extension.MIN_EXT;
23264 equationToGL[ MaxEquation ] = extension.MAX_EXT;
23265
23266 }
23267
23268 }
23269
23270 const factorToGL = {
23271 [ ZeroFactor ]: gl.ZERO,
23272 [ OneFactor ]: gl.ONE,
23273 [ SrcColorFactor ]: gl.SRC_COLOR,
23274 [ SrcAlphaFactor ]: gl.SRC_ALPHA,
23275 [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
23276 [ DstColorFactor ]: gl.DST_COLOR,
23277 [ DstAlphaFactor ]: gl.DST_ALPHA,
23278 [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
23279 [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
23280 [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
23281 [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
23282 [ ConstantColorFactor ]: gl.CONSTANT_COLOR,
23283 [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
23284 [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
23285 [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
23286 };
23287
23289
23290 if ( blending === NoBlending ) {
23291
23292 if ( currentBlendingEnabled === true ) {
23293
23294 disable( gl.BLEND );
23295 currentBlendingEnabled = false;
23296
23297 }
23298
23299 return;
23300
23301 }
23302
23303 if ( currentBlendingEnabled === false ) {
23304
23305 enable( gl.BLEND );
23307
23308 }
23309
23310 if ( blending !== CustomBlending ) {
23311
23313
23315
23316 gl.blendEquation( gl.FUNC_ADD );
23317
23320
23321 }
23322
23323 if ( premultipliedAlpha ) {
23324
23325 switch ( blending ) {
23326
23327 case NormalBlending:
23328 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23329 break;
23330
23331 case AdditiveBlending:
23332 gl.blendFunc( gl.ONE, gl.ONE );
23333 break;
23334
23336 gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23337 break;
23338
23339 case MultiplyBlending:
23340 gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
23341 break;
23342
23343 default:
23344 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23345 break;
23346
23347 }
23348
23349 } else {
23350
23351 switch ( blending ) {
23352
23353 case NormalBlending:
23354 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
23355 break;
23356
23357 case AdditiveBlending:
23358 gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
23359 break;
23360
23362 gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
23363 break;
23364
23365 case MultiplyBlending:
23366 gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
23367 break;
23368
23369 default:
23370 console.error( 'THREE.WebGLState: Invalid blending: ', blending );
23371 break;
23372
23373 }
23374
23375 }
23376
23377 currentBlendSrc = null;
23378 currentBlendDst = null;
23379 currentBlendSrcAlpha = null;
23380 currentBlendDstAlpha = null;
23381 currentBlendColor.set( 0, 0, 0 );
23383
23386
23387 }
23388
23389 return;
23390
23391 }
23392
23393 // custom blending
23394
23398
23400
23401 gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );
23402
23405
23406 }
23407
23409
23411
23416
23417 }
23418
23419 if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {
23420
23421 gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );
23422
23425
23426 }
23427
23430
23431 }
23432
23433 function setMaterial( material, frontFaceCW ) {
23434
23435 material.side === DoubleSide
23436 ? disable( gl.CULL_FACE )
23437 : enable( gl.CULL_FACE );
23438
23439 let flipSided = ( material.side === BackSide );
23440 if ( frontFaceCW ) flipSided = ! flipSided;
23441
23443
23444 ( material.blending === NormalBlending && material.transparent === false )
23446 : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );
23447
23448 depthBuffer.setFunc( material.depthFunc );
23449 depthBuffer.setTest( material.depthTest );
23450 depthBuffer.setMask( material.depthWrite );
23451 colorBuffer.setMask( material.colorWrite );
23452
23453 const stencilWrite = material.stencilWrite;
23454 stencilBuffer.setTest( stencilWrite );
23455 if ( stencilWrite ) {
23456
23457 stencilBuffer.setMask( material.stencilWriteMask );
23458 stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
23459 stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );
23460
23461 }
23462
23463 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
23464
23465 material.alphaToCoverage === true
23466 ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
23468
23469 }
23470
23471 //
23472
23473 function setFlipSided( flipSided ) {
23474
23475 if ( currentFlipSided !== flipSided ) {
23476
23477 if ( flipSided ) {
23478
23479 gl.frontFace( gl.CW );
23480
23481 } else {
23482
23483 gl.frontFace( gl.CCW );
23484
23485 }
23486
23488
23489 }
23490
23491 }
23492
23493 function setCullFace( cullFace ) {
23494
23495 if ( cullFace !== CullFaceNone ) {
23496
23497 enable( gl.CULL_FACE );
23498
23499 if ( cullFace !== currentCullFace ) {
23500
23501 if ( cullFace === CullFaceBack ) {
23502
23503 gl.cullFace( gl.BACK );
23504
23505 } else if ( cullFace === CullFaceFront ) {
23506
23507 gl.cullFace( gl.FRONT );
23508
23509 } else {
23510
23511 gl.cullFace( gl.FRONT_AND_BACK );
23512
23513 }
23514
23515 }
23516
23517 } else {
23518
23519 disable( gl.CULL_FACE );
23520
23521 }
23522
23524
23525 }
23526
23527 function setLineWidth( width ) {
23528
23529 if ( width !== currentLineWidth ) {
23530
23531 if ( lineWidthAvailable ) gl.lineWidth( width );
23532
23534
23535 }
23536
23537 }
23538
23540
23541 if ( polygonOffset ) {
23542
23543 enable( gl.POLYGON_OFFSET_FILL );
23544
23546
23547 gl.polygonOffset( factor, units );
23548
23551
23552 }
23553
23554 } else {
23555
23556 disable( gl.POLYGON_OFFSET_FILL );
23557
23558 }
23559
23560 }
23561
23562 function setScissorTest( scissorTest ) {
23563
23564 if ( scissorTest ) {
23565
23566 enable( gl.SCISSOR_TEST );
23567
23568 } else {
23569
23570 disable( gl.SCISSOR_TEST );
23571
23572 }
23573
23574 }
23575
23576 // texture
23577
23578 function activeTexture( webglSlot ) {
23579
23580 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
23581
23582 if ( currentTextureSlot !== webglSlot ) {
23583
23584 gl.activeTexture( webglSlot );
23586
23587 }
23588
23589 }
23590
23592
23593 if ( webglSlot === undefined ) {
23594
23595 if ( currentTextureSlot === null ) {
23596
23597 webglSlot = gl.TEXTURE0 + maxTextures - 1;
23598
23599 } else {
23600
23602
23603 }
23604
23605 }
23606
23608
23609 if ( boundTexture === undefined ) {
23610
23613
23614 }
23615
23616 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
23617
23618 if ( currentTextureSlot !== webglSlot ) {
23619
23620 gl.activeTexture( webglSlot );
23622
23623 }
23624
23625 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
23626
23627 boundTexture.type = webglType;
23628 boundTexture.texture = webglTexture;
23629
23630 }
23631
23632 }
23633
23634 function unbindTexture() {
23635
23637
23638 if ( boundTexture !== undefined && boundTexture.type !== undefined ) {
23639
23640 gl.bindTexture( boundTexture.type, null );
23641
23642 boundTexture.type = undefined;
23643 boundTexture.texture = undefined;
23644
23645 }
23646
23647 }
23648
23649 function compressedTexImage2D() {
23650
23651 try {
23652
23653 gl.compressedTexImage2D.apply( gl, arguments );
23654
23655 } catch ( error ) {
23656
23657 console.error( 'THREE.WebGLState:', error );
23658
23659 }
23660
23661 }
23662
23663 function compressedTexImage3D() {
23664
23665 try {
23666
23667 gl.compressedTexImage3D.apply( gl, arguments );
23668
23669 } catch ( error ) {
23670
23671 console.error( 'THREE.WebGLState:', error );
23672
23673 }
23674
23675 }
23676
23677 function texSubImage2D() {
23678
23679 try {
23680
23681 gl.texSubImage2D.apply( gl, arguments );
23682
23683 } catch ( error ) {
23684
23685 console.error( 'THREE.WebGLState:', error );
23686
23687 }
23688
23689 }
23690
23691 function texSubImage3D() {
23692
23693 try {
23694
23695 gl.texSubImage3D.apply( gl, arguments );
23696
23697 } catch ( error ) {
23698
23699 console.error( 'THREE.WebGLState:', error );
23700
23701 }
23702
23703 }
23704
23705 function compressedTexSubImage2D() {
23706
23707 try {
23708
23709 gl.compressedTexSubImage2D.apply( gl, arguments );
23710
23711 } catch ( error ) {
23712
23713 console.error( 'THREE.WebGLState:', error );
23714
23715 }
23716
23717 }
23718
23719 function compressedTexSubImage3D() {
23720
23721 try {
23722
23723 gl.compressedTexSubImage3D.apply( gl, arguments );
23724
23725 } catch ( error ) {
23726
23727 console.error( 'THREE.WebGLState:', error );
23728
23729 }
23730
23731 }
23732
23733 function texStorage2D() {
23734
23735 try {
23736
23737 gl.texStorage2D.apply( gl, arguments );
23738
23739 } catch ( error ) {
23740
23741 console.error( 'THREE.WebGLState:', error );
23742
23743 }
23744
23745 }
23746
23747 function texStorage3D() {
23748
23749 try {
23750
23751 gl.texStorage3D.apply( gl, arguments );
23752
23753 } catch ( error ) {
23754
23755 console.error( 'THREE.WebGLState:', error );
23756
23757 }
23758
23759 }
23760
23761 function texImage2D() {
23762
23763 try {
23764
23765 gl.texImage2D.apply( gl, arguments );
23766
23767 } catch ( error ) {
23768
23769 console.error( 'THREE.WebGLState:', error );
23770
23771 }
23772
23773 }
23774
23775 function texImage3D() {
23776
23777 try {
23778
23779 gl.texImage3D.apply( gl, arguments );
23780
23781 } catch ( error ) {
23782
23783 console.error( 'THREE.WebGLState:', error );
23784
23785 }
23786
23787 }
23788
23789 //
23790
23791 function scissor( scissor ) {
23792
23793 if ( currentScissor.equals( scissor ) === false ) {
23794
23795 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
23796 currentScissor.copy( scissor );
23797
23798 }
23799
23800 }
23801
23802 function viewport( viewport ) {
23803
23804 if ( currentViewport.equals( viewport ) === false ) {
23805
23806 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
23807 currentViewport.copy( viewport );
23808
23809 }
23810
23811 }
23812
23814
23816
23817 if ( mapping === undefined ) {
23818
23819 mapping = new WeakMap();
23820
23822
23823 }
23824
23826
23827 if ( blockIndex === undefined ) {
23828
23829 blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );
23830
23832
23833 }
23834
23835 }
23836
23838
23839 const mapping = uboProgramMap.get( program );
23840 const blockIndex = mapping.get( uniformsGroup );
23841
23842 if ( uboBindings.get( program ) !== blockIndex ) {
23843
23844 // bind shader specific block index to global block point
23845 gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );
23846
23848
23849 }
23850
23851 }
23852
23853 //
23854
23855 function reset() {
23856
23857 // reset state
23858
23859 gl.disable( gl.BLEND );
23860 gl.disable( gl.CULL_FACE );
23861 gl.disable( gl.DEPTH_TEST );
23862 gl.disable( gl.POLYGON_OFFSET_FILL );
23863 gl.disable( gl.SCISSOR_TEST );
23864 gl.disable( gl.STENCIL_TEST );
23865 gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
23866
23867 gl.blendEquation( gl.FUNC_ADD );
23868 gl.blendFunc( gl.ONE, gl.ZERO );
23869 gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
23870 gl.blendColor( 0, 0, 0, 0 );
23871
23872 gl.colorMask( true, true, true, true );
23873 gl.clearColor( 0, 0, 0, 0 );
23874
23875 gl.depthMask( true );
23876 gl.depthFunc( gl.LESS );
23877 gl.clearDepth( 1 );
23878
23879 gl.stencilMask( 0xffffffff );
23880 gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
23881 gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
23882 gl.clearStencil( 0 );
23883
23884 gl.cullFace( gl.BACK );
23885 gl.frontFace( gl.CCW );
23886
23887 gl.polygonOffset( 0, 0 );
23888
23889 gl.activeTexture( gl.TEXTURE0 );
23890
23891 gl.bindFramebuffer( gl.FRAMEBUFFER, null );
23892
23893 if ( isWebGL2 === true ) {
23894
23895 gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
23896 gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );
23897
23898 }
23899
23900 gl.useProgram( null );
23901
23902 gl.lineWidth( 1 );
23903
23904 gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
23905 gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
23906
23907 // reset internals
23908
23910
23911 currentTextureSlot = null;
23913
23916 defaultDrawbuffers = [];
23917
23918 currentProgram = null;
23919
23920 currentBlendingEnabled = false;
23921 currentBlending = null;
23922 currentBlendEquation = null;
23923 currentBlendSrc = null;
23924 currentBlendDst = null;
23926 currentBlendSrcAlpha = null;
23927 currentBlendDstAlpha = null;
23928 currentBlendColor = new Color( 0, 0, 0 );
23931
23932 currentFlipSided = null;
23933 currentCullFace = null;
23934
23935 currentLineWidth = null;
23936
23939
23940 currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
23941 currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );
23942
23943 colorBuffer.reset();
23944 depthBuffer.reset();
23945 stencilBuffer.reset();
23946
23947 }
23948
23949 return {
23950
23951 buffers: {
23955 },
23956
23957 enable: enable,
23959
23962
23964
23967
23970
23973
23975
23983
23986
23993
23996
23997 reset: reset
23998
23999 };
24000
24001 }
24002
24003 function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
24004
24005 const isWebGL2 = capabilities.isWebGL2;
24006 const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;
24007 const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent );
24008
24009 const _videoTextures = new WeakMap();
24010 let _canvas;
24011
24012 const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source
24013
24014 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
24015 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
24016 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
24017
24018 let useOffscreenCanvas = false;
24019
24020 try {
24021
24022 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
24023 // eslint-disable-next-line compat/compat
24024 && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
24025
24026 } catch ( err ) {
24027
24028 // Ignore any errors
24029
24030 }
24031
24032 function createCanvas( width, height ) {
24033
24034 // Use OffscreenCanvas when available. Specially needed in web workers
24035
24036 return useOffscreenCanvas ?
24037 // eslint-disable-next-line compat/compat
24038 new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );
24039
24040 }
24041
24042 function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
24043
24044 let scale = 1;
24045
24046 // handle case if texture exceeds max size
24047
24048 if ( image.width > maxSize || image.height > maxSize ) {
24049
24050 scale = maxSize / Math.max( image.width, image.height );
24051
24052 }
24053
24054 // only perform resize if necessary
24055
24056 if ( scale < 1 || needsPowerOfTwo === true ) {
24057
24058 // only perform resize for certain image types
24059
24060 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
24062 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
24063
24064 const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor;
24065
24066 const width = floor( scale * image.width );
24067 const height = floor( scale * image.height );
24068
24070
24071 // cube textures can't reuse the same canvas
24072
24074
24075 canvas.width = width;
24076 canvas.height = height;
24077
24078 const context = canvas.getContext( '2d' );
24079 context.drawImage( image, 0, 0, width, height );
24080
24081 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
24082
24083 return canvas;
24084
24085 } else {
24086
24087 if ( 'data' in image ) {
24088
24089 console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
24090
24091 }
24092
24093 return image;
24094
24095 }
24096
24097 }
24098
24099 return image;
24100
24101 }
24102
24103 function isPowerOfTwo$1( image ) {
24104
24105 return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height );
24106
24107 }
24108
24109 function textureNeedsPowerOfTwo( texture ) {
24110
24111 if ( isWebGL2 ) return false;
24112
24113 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
24114 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
24115
24116 }
24117
24119
24120 return texture.generateMipmaps && supportsMips &&
24121 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
24122
24123 }
24124
24125 function generateMipmap( target ) {
24126
24127 _gl.generateMipmap( target );
24128
24129 }
24130
24132
24133 if ( isWebGL2 === false ) return glFormat;
24134
24135 if ( internalFormatName !== null ) {
24136
24137 if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
24138
24139 console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
24140
24141 }
24142
24144
24145 if ( glFormat === _gl.RED ) {
24146
24147 if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
24148 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
24149 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
24150
24151 }
24152
24153 if ( glFormat === _gl.RED_INTEGER ) {
24154
24155 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI;
24156 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI;
24157 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI;
24158 if ( glType === _gl.BYTE ) internalFormat = _gl.R8I;
24159 if ( glType === _gl.SHORT ) internalFormat = _gl.R16I;
24160 if ( glType === _gl.INT ) internalFormat = _gl.R32I;
24161
24162 }
24163
24164 if ( glFormat === _gl.RG ) {
24165
24166 if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;
24167 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;
24168 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;
24169
24170 }
24171
24172 if ( glFormat === _gl.RGBA ) {
24173
24175
24176 if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
24177 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
24178 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
24179 if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;
24180 if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;
24181
24182 }
24183
24184 if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||
24185 internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
24186 internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {
24187
24188 extensions.get( 'EXT_color_buffer_float' );
24189
24190 }
24191
24192 return internalFormat;
24193
24194 }
24195
24196 function getMipLevels( texture, image, supportsMips ) {
24197
24198 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {
24199
24200 return Math.log2( Math.max( image.width, image.height ) ) + 1;
24201
24202 } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {
24203
24204 // user-defined mipmaps
24205
24206 return texture.mipmaps.length;
24207
24208 } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {
24209
24210 return image.mipmaps.length;
24211
24212 } else {
24213
24214 // texture without mipmaps (only base level)
24215
24216 return 1;
24217
24218 }
24219
24220 }
24221
24222 // Fallback filters for non-power-of-2 textures
24223
24224 function filterFallback( f ) {
24225
24227
24228 return _gl.NEAREST;
24229
24230 }
24231
24232 return _gl.LINEAR;
24233
24234 }
24235
24236 //
24237
24238 function onTextureDispose( event ) {
24239
24240 const texture = event.target;
24241
24242 texture.removeEventListener( 'dispose', onTextureDispose );
24243
24245
24246 if ( texture.isVideoTexture ) {
24247
24248 _videoTextures.delete( texture );
24249
24250 }
24251
24252 }
24253
24254 function onRenderTargetDispose( event ) {
24255
24256 const renderTarget = event.target;
24257
24258 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
24259
24261
24262 }
24263
24264 //
24265
24266 function deallocateTexture( texture ) {
24267
24268 const textureProperties = properties.get( texture );
24269
24270 if ( textureProperties.__webglInit === undefined ) return;
24271
24272 // check if it's necessary to remove the WebGLTexture object
24273
24274 const source = texture.source;
24275 const webglTextures = _sources.get( source );
24276
24277 if ( webglTextures ) {
24278
24279 const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24280 webglTexture.usedTimes --;
24281
24282 // the WebGLTexture object is not used anymore, remove it
24283
24284 if ( webglTexture.usedTimes === 0 ) {
24285
24287
24288 }
24289
24290 // remove the weak map entry if no WebGLTexture uses the source anymore
24291
24292 if ( Object.keys( webglTextures ).length === 0 ) {
24293
24294 _sources.delete( source );
24295
24296 }
24297
24298 }
24299
24300 properties.remove( texture );
24301
24302 }
24303
24304 function deleteTexture( texture ) {
24305
24306 const textureProperties = properties.get( texture );
24307 _gl.deleteTexture( textureProperties.__webglTexture );
24308
24309 const source = texture.source;
24310 const webglTextures = _sources.get( source );
24311 delete webglTextures[ textureProperties.__cacheKey ];
24312
24313 info.memory.textures --;
24314
24315 }
24316
24318
24319 const texture = renderTarget.texture;
24320
24321 const renderTargetProperties = properties.get( renderTarget );
24322 const textureProperties = properties.get( texture );
24323
24324 if ( textureProperties.__webglTexture !== undefined ) {
24325
24326 _gl.deleteTexture( textureProperties.__webglTexture );
24327
24328 info.memory.textures --;
24329
24330 }
24331
24332 if ( renderTarget.depthTexture ) {
24333
24334 renderTarget.depthTexture.dispose();
24335
24336 }
24337
24338 if ( renderTarget.isWebGLCubeRenderTarget ) {
24339
24340 for ( let i = 0; i < 6; i ++ ) {
24341
24342 if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {
24343
24344 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] );
24345
24346 } else {
24347
24348 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
24349
24350 }
24351
24352 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
24353
24354 }
24355
24356 } else {
24357
24358 if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) {
24359
24360 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] );
24361
24362 } else {
24363
24364 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
24365
24366 }
24367
24368 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
24369 if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
24370
24371 if ( renderTargetProperties.__webglColorRenderbuffer ) {
24372
24373 for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {
24374
24375 if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );
24376
24377 }
24378
24379 }
24380
24381 if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
24382
24383 }
24384
24385 if ( renderTarget.isWebGLMultipleRenderTargets ) {
24386
24387 for ( let i = 0, il = texture.length; i < il; i ++ ) {
24388
24389 const attachmentProperties = properties.get( texture[ i ] );
24390
24391 if ( attachmentProperties.__webglTexture ) {
24392
24393 _gl.deleteTexture( attachmentProperties.__webglTexture );
24394
24395 info.memory.textures --;
24396
24397 }
24398
24399 properties.remove( texture[ i ] );
24400
24401 }
24402
24403 }
24404
24405 properties.remove( texture );
24406 properties.remove( renderTarget );
24407
24408 }
24409
24410 //
24411
24412 let textureUnits = 0;
24413
24414 function resetTextureUnits() {
24415
24416 textureUnits = 0;
24417
24418 }
24419
24420 function allocateTextureUnit() {
24421
24422 const textureUnit = textureUnits;
24423
24424 if ( textureUnit >= capabilities.maxTextures ) {
24425
24426 console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
24427
24428 }
24429
24430 textureUnits += 1;
24431
24432 return textureUnit;
24433
24434 }
24435
24436 function getTextureCacheKey( texture ) {
24437
24438 const array = [];
24439
24440 array.push( texture.wrapS );
24441 array.push( texture.wrapT );
24442 array.push( texture.wrapR || 0 );
24443 array.push( texture.magFilter );
24444 array.push( texture.minFilter );
24445 array.push( texture.anisotropy );
24446 array.push( texture.internalFormat );
24447 array.push( texture.format );
24448 array.push( texture.type );
24449 array.push( texture.generateMipmaps );
24450 array.push( texture.premultiplyAlpha );
24451 array.push( texture.flipY );
24452 array.push( texture.unpackAlignment );
24453 array.push( texture.colorSpace );
24454
24455 return array.join();
24456
24457 }
24458
24459 //
24460
24461 function setTexture2D( texture, slot ) {
24462
24463 const textureProperties = properties.get( texture );
24464
24465 if ( texture.isVideoTexture ) updateVideoTexture( texture );
24466
24467 if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {
24468
24469 const image = texture.image;
24470
24471 if ( image === null ) {
24472
24473 console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );
24474
24475 } else if ( image.complete === false ) {
24476
24477 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
24478
24479 } else {
24480
24482 return;
24483
24484 }
24485
24486 }
24487
24488 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24489
24490 }
24491
24492 function setTexture2DArray( texture, slot ) {
24493
24494 const textureProperties = properties.get( texture );
24495
24496 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24497
24499 return;
24500
24501 }
24502
24503 state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24504
24505 }
24506
24507 function setTexture3D( texture, slot ) {
24508
24509 const textureProperties = properties.get( texture );
24510
24511 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24512
24514 return;
24515
24516 }
24517
24518 state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24519
24520 }
24521
24522 function setTextureCube( texture, slot ) {
24523
24524 const textureProperties = properties.get( texture );
24525
24526 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
24527
24529 return;
24530
24531 }
24532
24533 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24534
24535 }
24536
24537 const wrappingToGL = {
24538 [ RepeatWrapping ]: _gl.REPEAT,
24539 [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
24540 [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
24541 };
24542
24543 const filterToGL = {
24544 [ NearestFilter ]: _gl.NEAREST,
24545 [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
24546 [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,
24547
24548 [ LinearFilter ]: _gl.LINEAR,
24549 [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
24550 [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
24551 };
24552
24553 const compareToGL = {
24554 [ NeverCompare ]: _gl.NEVER,
24555 [ AlwaysCompare ]: _gl.ALWAYS,
24556 [ LessCompare ]: _gl.LESS,
24557 [ LessEqualCompare ]: _gl.LEQUAL,
24558 [ EqualCompare ]: _gl.EQUAL,
24559 [ GreaterEqualCompare ]: _gl.GEQUAL,
24560 [ GreaterCompare ]: _gl.GREATER,
24561 [ NotEqualCompare ]: _gl.NOTEQUAL
24562 };
24563
24565
24566 if ( supportsMips ) {
24567
24568 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
24569 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );
24570
24571 if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24572
24573 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );
24574
24575 }
24576
24577 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
24578 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );
24579
24580 } else {
24581
24582 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
24583 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
24584
24585 if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
24586
24587 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE );
24588
24589 }
24590
24591 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
24592
24593 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
24594
24595 }
24596
24597 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
24598 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
24599
24600 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
24601
24602 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
24603
24604 }
24605
24606 }
24607
24608 if ( texture.compareFunction ) {
24609
24610 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE );
24611 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );
24612
24613 }
24614
24615 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
24616
24617 const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
24618
24619 if ( texture.magFilter === NearestFilter ) return;
24620 if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;
24621 if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
24622 if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only
24623
24624 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
24625
24626 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
24627 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
24628
24629 }
24630
24631 }
24632
24633 }
24634
24636
24637 let forceUpload = false;
24638
24639 if ( textureProperties.__webglInit === undefined ) {
24640
24641 textureProperties.__webglInit = true;
24642
24643 texture.addEventListener( 'dispose', onTextureDispose );
24644
24645 }
24646
24647 // create Source <-> WebGLTextures mapping if necessary
24648
24649 const source = texture.source;
24651
24652 if ( webglTextures === undefined ) {
24653
24654 webglTextures = {};
24656
24657 }
24658
24659 // check if there is already a WebGLTexture object for the given texture parameters
24660
24662
24663 if ( textureCacheKey !== textureProperties.__cacheKey ) {
24664
24665 // if not, create a new instance of WebGLTexture
24666
24668
24669 // create new entry
24670
24672 texture: _gl.createTexture(),
24673 usedTimes: 0
24674 };
24675
24676 info.memory.textures ++;
24677
24678 // when a new instance of WebGLTexture was created, a texture upload is required
24679 // even if the image contents are identical
24680
24681 forceUpload = true;
24682
24683 }
24684
24685 webglTextures[ textureCacheKey ].usedTimes ++;
24686
24687 // every time the texture cache key changes, it's necessary to check if an instance of
24688 // WebGLTexture can be deleted in order to avoid a memory leak.
24689
24690 const webglTexture = webglTextures[ textureProperties.__cacheKey ];
24691
24692 if ( webglTexture !== undefined ) {
24693
24694 webglTextures[ textureProperties.__cacheKey ].usedTimes --;
24695
24696 if ( webglTexture.usedTimes === 0 ) {
24697
24699
24700 }
24701
24702 }
24703
24704 // store references to cache key and WebGLTexture object
24705
24707 textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;
24708
24709 }
24710
24711 return forceUpload;
24712
24713 }
24714
24716
24717 let textureType = _gl.TEXTURE_2D;
24718
24719 if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY;
24720 if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;
24721
24723 const source = texture.source;
24724
24725 state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
24726
24727 const sourceProperties = properties.get( source );
24728
24729 if ( source.version !== sourceProperties.__version || forceUpload === true ) {
24730
24731 state.activeTexture( _gl.TEXTURE0 + slot );
24732
24733 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
24734 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
24735 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
24736
24737 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
24738 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
24739 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
24740 _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
24741
24742 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false;
24743 let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize );
24745
24747 glFormat = utils.convert( texture.format, texture.colorSpace );
24748
24749 let glType = utils.convert( texture.type ),
24750 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
24751
24753
24754 let mipmap;
24755 const mipmaps = texture.mipmaps;
24756
24757 const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format );
24758 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
24760
24761 if ( texture.isDepthTexture ) {
24762
24763 // populate depth texture with dummy data
24764
24765 glInternalFormat = _gl.DEPTH_COMPONENT;
24766
24767 if ( isWebGL2 ) {
24768
24769 if ( texture.type === FloatType ) {
24770
24771 glInternalFormat = _gl.DEPTH_COMPONENT32F;
24772
24773 } else if ( texture.type === UnsignedIntType ) {
24774
24775 glInternalFormat = _gl.DEPTH_COMPONENT24;
24776
24777 } else if ( texture.type === UnsignedInt248Type ) {
24778
24779 glInternalFormat = _gl.DEPTH24_STENCIL8;
24780
24781 } else {
24782
24783 glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D
24784
24785 }
24786
24787 } else {
24788
24789 if ( texture.type === FloatType ) {
24790
24791 console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
24792
24793 }
24794
24795 }
24796
24797 // validation checks for WebGL 1
24798
24799 if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24800
24801 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24802 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
24803 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24804 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
24805
24806 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
24807
24808 texture.type = UnsignedIntType;
24809 glType = utils.convert( texture.type );
24810
24811 }
24812
24813 }
24814
24815 if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
24816
24817 // Depth stencil textures need the DEPTH_STENCIL internal format
24818 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24819 glInternalFormat = _gl.DEPTH_STENCIL;
24820
24821 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
24822 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
24823 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
24824 if ( texture.type !== UnsignedInt248Type ) {
24825
24826 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
24827
24829 glType = utils.convert( texture.type );
24830
24831 }
24832
24833 }
24834
24835 //
24836
24837 if ( allocateMemory ) {
24838
24839 if ( useTexStorage ) {
24840
24841 state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );
24842
24843 } else {
24844
24845 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
24846
24847 }
24848
24849 }
24850
24851 } else if ( texture.isDataTexture ) {
24852
24853 // use manually created mipmaps if available
24854 // if there are no manual mipmaps
24855 // set 0 level mipmap and then use GL to generate other mipmap levels
24856
24857 if ( mipmaps.length > 0 && supportsMips ) {
24858
24859 if ( useTexStorage && allocateMemory ) {
24860
24861 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24862
24863 }
24864
24865 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24866
24867 mipmap = mipmaps[ i ];
24868
24869 if ( useTexStorage ) {
24870
24871 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24872
24873 } else {
24874
24875 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24876
24877 }
24878
24879 }
24880
24881 texture.generateMipmaps = false;
24882
24883 } else {
24884
24885 if ( useTexStorage ) {
24886
24887 if ( allocateMemory ) {
24888
24889 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
24890
24891 }
24892
24893 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
24894
24895 } else {
24896
24897 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
24898
24899 }
24900
24901 }
24902
24903 } else if ( texture.isCompressedTexture ) {
24904
24905 if ( texture.isCompressedArrayTexture ) {
24906
24907 if ( useTexStorage && allocateMemory ) {
24908
24909 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );
24910
24911 }
24912
24913 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24914
24915 mipmap = mipmaps[ i ];
24916
24917 if ( texture.format !== RGBAFormat ) {
24918
24919 if ( glFormat !== null ) {
24920
24921 if ( useTexStorage ) {
24922
24923 state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );
24924
24925 } else {
24926
24927 state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );
24928
24929 }
24930
24931 } else {
24932
24933 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24934
24935 }
24936
24937 } else {
24938
24939 if ( useTexStorage ) {
24940
24941 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );
24942
24943 } else {
24944
24945 state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );
24946
24947 }
24948
24949 }
24950
24951 }
24952
24953 } else {
24954
24955 if ( useTexStorage && allocateMemory ) {
24956
24957 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
24958
24959 }
24960
24961 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
24962
24963 mipmap = mipmaps[ i ];
24964
24965 if ( texture.format !== RGBAFormat ) {
24966
24967 if ( glFormat !== null ) {
24968
24969 if ( useTexStorage ) {
24970
24971 state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
24972
24973 } else {
24974
24975 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
24976
24977 }
24978
24979 } else {
24980
24981 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
24982
24983 }
24984
24985 } else {
24986
24987 if ( useTexStorage ) {
24988
24989 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
24990
24991 } else {
24992
24993 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
24994
24995 }
24996
24997 }
24998
24999 }
25000
25001 }
25002
25003 } else if ( texture.isDataArrayTexture ) {
25004
25005 if ( useTexStorage ) {
25006
25007 if ( allocateMemory ) {
25008
25009 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );
25010
25011 }
25012
25013 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25014
25015 } else {
25016
25017 state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25018
25019 }
25020
25021 } else if ( texture.isData3DTexture ) {
25022
25023 if ( useTexStorage ) {
25024
25025 if ( allocateMemory ) {
25026
25027 state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );
25028
25029 }
25030
25031 state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
25032
25033 } else {
25034
25035 state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
25036
25037 }
25038
25039 } else if ( texture.isFramebufferTexture ) {
25040
25041 if ( allocateMemory ) {
25042
25043 if ( useTexStorage ) {
25044
25045 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25046
25047 } else {
25048
25049 let width = image.width, height = image.height;
25050
25051 for ( let i = 0; i < levels; i ++ ) {
25052
25053 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );
25054
25055 width >>= 1;
25056 height >>= 1;
25057
25058 }
25059
25060 }
25061
25062 }
25063
25064 } else {
25065
25066 // regular Texture (image, video, canvas)
25067
25068 // use manually created mipmaps if available
25069 // if there are no manual mipmaps
25070 // set 0 level mipmap and then use GL to generate other mipmap levels
25071
25072 if ( mipmaps.length > 0 && supportsMips ) {
25073
25074 if ( useTexStorage && allocateMemory ) {
25075
25076 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
25077
25078 }
25079
25080 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
25081
25082 mipmap = mipmaps[ i ];
25083
25084 if ( useTexStorage ) {
25085
25086 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );
25087
25088 } else {
25089
25090 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
25091
25092 }
25093
25094 }
25095
25096 texture.generateMipmaps = false;
25097
25098 } else {
25099
25100 if ( useTexStorage ) {
25101
25102 if ( allocateMemory ) {
25103
25104 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
25105
25106 }
25107
25108 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );
25109
25110 } else {
25111
25112 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
25113
25114 }
25115
25116 }
25117
25118 }
25119
25121
25123
25124 }
25125
25126 sourceProperties.__version = source.version;
25127
25128 if ( texture.onUpdate ) texture.onUpdate( texture );
25129
25130 }
25131
25132 textureProperties.__version = texture.version;
25133
25134 }
25135
25137
25138 if ( texture.image.length !== 6 ) return;
25139
25141 const source = texture.source;
25142
25143 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
25144
25145 const sourceProperties = properties.get( source );
25146
25147 if ( source.version !== sourceProperties.__version || forceUpload === true ) {
25148
25149 state.activeTexture( _gl.TEXTURE0 + slot );
25150
25151 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
25152 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
25153 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
25154
25155 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
25156 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
25157 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
25158 _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
25159
25160 const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );
25161 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
25162
25163 const cubeImage = [];
25164
25165 for ( let i = 0; i < 6; i ++ ) {
25166
25167 if ( ! isCompressed && ! isDataTexture ) {
25168
25169 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize );
25170
25171 } else {
25172
25173 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
25174
25175 }
25176
25178
25179 }
25180
25181 const image = cubeImage[ 0 ],
25183 glFormat = utils.convert( texture.format, texture.colorSpace ),
25184 glType = utils.convert( texture.type ),
25185 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25186
25187 const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true );
25188 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
25190
25191 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25192
25193 let mipmaps;
25194
25195 if ( isCompressed ) {
25196
25197 if ( useTexStorage && allocateMemory ) {
25198
25199 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );
25200
25201 }
25202
25203 for ( let i = 0; i < 6; i ++ ) {
25204
25205 mipmaps = cubeImage[ i ].mipmaps;
25206
25207 for ( let j = 0; j < mipmaps.length; j ++ ) {
25208
25209 const mipmap = mipmaps[ j ];
25210
25211 if ( texture.format !== RGBAFormat ) {
25212
25213 if ( glFormat !== null ) {
25214
25215 if ( useTexStorage ) {
25216
25217 state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
25218
25219 } else {
25220
25221 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
25222
25223 }
25224
25225 } else {
25226
25227 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
25228
25229 }
25230
25231 } else {
25232
25233 if ( useTexStorage ) {
25234
25235 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
25236
25237 } else {
25238
25239 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
25240
25241 }
25242
25243 }
25244
25245 }
25246
25247 }
25248
25249 } else {
25250
25251 mipmaps = texture.mipmaps;
25252
25253 if ( useTexStorage && allocateMemory ) {
25254
25255 // TODO: Uniformly handle mipmap definitions
25256 // Normal textures and compressed cube textures define base level + mips with their mipmap array
25257 // Uncompressed cube textures use their mipmap array only for mips (no base level)
25258
25259 if ( mipmaps.length > 0 ) levels ++;
25260
25261 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height );
25262
25263 }
25264
25265 for ( let i = 0; i < 6; i ++ ) {
25266
25267 if ( isDataTexture ) {
25268
25269 if ( useTexStorage ) {
25270
25271 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );
25272
25273 } else {
25274
25275 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
25276
25277 }
25278
25279 for ( let j = 0; j < mipmaps.length; j ++ ) {
25280
25281 const mipmap = mipmaps[ j ];
25282 const mipmapImage = mipmap.image[ i ].image;
25283
25284 if ( useTexStorage ) {
25285
25286 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );
25287
25288 } else {
25289
25290 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
25291
25292 }
25293
25294 }
25295
25296 } else {
25297
25298 if ( useTexStorage ) {
25299
25300 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );
25301
25302 } else {
25303
25304 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
25305
25306 }
25307
25308 for ( let j = 0; j < mipmaps.length; j ++ ) {
25309
25310 const mipmap = mipmaps[ j ];
25311
25312 if ( useTexStorage ) {
25313
25314 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );
25315
25316 } else {
25317
25318 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
25319
25320 }
25321
25322 }
25323
25324 }
25325
25326 }
25327
25328 }
25329
25331
25332 // We assume images for cube map have the same size.
25333 generateMipmap( _gl.TEXTURE_CUBE_MAP );
25334
25335 }
25336
25337 sourceProperties.__version = source.version;
25338
25339 if ( texture.onUpdate ) texture.onUpdate( texture );
25340
25341 }
25342
25343 textureProperties.__version = texture.version;
25344
25345 }
25346
25347 // Render targets
25348
25349 // Setup storage for target texture and bind it to correct framebuffer
25351
25352 const glFormat = utils.convert( texture.format, texture.colorSpace );
25353 const glType = utils.convert( texture.type );
25354 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25355 const renderTargetProperties = properties.get( renderTarget );
25356
25357 if ( ! renderTargetProperties.__hasExternalTextures ) {
25358
25359 const width = Math.max( 1, renderTarget.width >> level );
25360 const height = Math.max( 1, renderTarget.height >> level );
25361
25362 if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
25363
25364 state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null );
25365
25366 } else {
25367
25368 state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null );
25369
25370 }
25371
25372 }
25373
25374 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25375
25377
25378 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
25379
25380 } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753
25381
25382 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );
25383
25384 }
25385
25386 state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25387
25388 }
25389
25390
25391 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
25393
25394 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
25395
25396 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
25397
25398 let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16;
25399
25401
25402 const depthTexture = renderTarget.depthTexture;
25403
25404 if ( depthTexture && depthTexture.isDepthTexture ) {
25405
25406 if ( depthTexture.type === FloatType ) {
25407
25408 glInternalFormat = _gl.DEPTH_COMPONENT32F;
25409
25410 } else if ( depthTexture.type === UnsignedIntType ) {
25411
25412 glInternalFormat = _gl.DEPTH_COMPONENT24;
25413
25414 }
25415
25416 }
25417
25419
25421
25422 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25423
25424 } else {
25425
25426 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25427
25428 }
25429
25430 } else {
25431
25432 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25433
25434 }
25435
25436 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25437
25438 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
25439
25441
25442 if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25443
25444 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25445
25446 } else if ( useMultisampledRTT( renderTarget ) ) {
25447
25448 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
25449
25450 } else {
25451
25452 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
25453
25454 }
25455
25456
25457 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
25458
25459 } else {
25460
25461 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25462
25463 for ( let i = 0; i < textures.length; i ++ ) {
25464
25465 const texture = textures[ i ];
25466
25467 const glFormat = utils.convert( texture.format, texture.colorSpace );
25468 const glType = utils.convert( texture.type );
25469 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
25471
25472 if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
25473
25474 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25475
25476 } else if ( useMultisampledRTT( renderTarget ) ) {
25477
25478 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25479
25480 } else {
25481
25482 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
25483
25484 }
25485
25486 }
25487
25488 }
25489
25490 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25491
25492 }
25493
25494 // Setup resources for a Depth Texture for a FBO (needs an extension)
25496
25497 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
25498 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
25499
25500 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25501
25502 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
25503
25504 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
25505
25506 }
25507
25508 // upload an empty depth texture with framebuffer size
25509 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
25510 renderTarget.depthTexture.image.width !== renderTarget.width ||
25511 renderTarget.depthTexture.image.height !== renderTarget.height ) {
25512
25513 renderTarget.depthTexture.image.width = renderTarget.width;
25514 renderTarget.depthTexture.image.height = renderTarget.height;
25515 renderTarget.depthTexture.needsUpdate = true;
25516
25517 }
25518
25519 setTexture2D( renderTarget.depthTexture, 0 );
25520
25521 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
25523
25524 if ( renderTarget.depthTexture.format === DepthFormat ) {
25525
25527
25528 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25529
25530 } else {
25531
25532 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25533
25534 }
25535
25536 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
25537
25539
25540 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
25541
25542 } else {
25543
25544 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
25545
25546 }
25547
25548 } else {
25549
25550 throw new Error( 'Unknown depthTexture format' );
25551
25552 }
25553
25554 }
25555
25556 // Setup GL resources for a non-texture depth buffer
25558
25559 const renderTargetProperties = properties.get( renderTarget );
25560 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25561
25562 if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {
25563
25564 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
25565
25567
25568 } else {
25569
25570 if ( isCube ) {
25571
25572 renderTargetProperties.__webglDepthbuffer = [];
25573
25574 for ( let i = 0; i < 6; i ++ ) {
25575
25576 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
25577 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
25578 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
25579
25580 }
25581
25582 } else {
25583
25584 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25585 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
25586 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
25587
25588 }
25589
25590 }
25591
25592 state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25593
25594 }
25595
25596 // rebind framebuffer with external textures
25598
25599 const renderTargetProperties = properties.get( renderTarget );
25600
25601 if ( colorTexture !== undefined ) {
25602
25603 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );
25604
25605 }
25606
25607 if ( depthTexture !== undefined ) {
25608
25610
25611 }
25612
25613 }
25614
25615 // Set up GL resources for the render target
25616 function setupRenderTarget( renderTarget ) {
25617
25618 const texture = renderTarget.texture;
25619
25620 const renderTargetProperties = properties.get( renderTarget );
25621 const textureProperties = properties.get( texture );
25622
25623 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
25624
25625 if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
25626
25627 if ( textureProperties.__webglTexture === undefined ) {
25628
25629 textureProperties.__webglTexture = _gl.createTexture();
25630
25631 }
25632
25633 textureProperties.__version = texture.version;
25634 info.memory.textures ++;
25635
25636 }
25637
25638 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
25639 const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25641
25642 // Setup framebuffer
25643
25644 if ( isCube ) {
25645
25646 renderTargetProperties.__webglFramebuffer = [];
25647
25648 for ( let i = 0; i < 6; i ++ ) {
25649
25650 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25651
25652 renderTargetProperties.__webglFramebuffer[ i ] = [];
25653
25654 for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25655
25656 renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer();
25657
25658 }
25659
25660 } else {
25661
25662 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
25663
25664 }
25665
25666 }
25667
25668 } else {
25669
25670 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25671
25672 renderTargetProperties.__webglFramebuffer = [];
25673
25674 for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25675
25676 renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer();
25677
25678 }
25679
25680 } else {
25681
25682 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
25683
25684 }
25685
25687
25688 if ( capabilities.drawBuffers ) {
25689
25690 const textures = renderTarget.texture;
25691
25692 for ( let i = 0, il = textures.length; i < il; i ++ ) {
25693
25694 const attachmentProperties = properties.get( textures[ i ] );
25695
25696 if ( attachmentProperties.__webglTexture === undefined ) {
25697
25698 attachmentProperties.__webglTexture = _gl.createTexture();
25699
25700 info.memory.textures ++;
25701
25702 }
25703
25704 }
25705
25706 } else {
25707
25708 console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' );
25709
25710 }
25711
25712 }
25713
25714 if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25715
25717
25718 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
25719 renderTargetProperties.__webglColorRenderbuffer = [];
25720
25721 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25722
25723 for ( let i = 0; i < textures.length; i ++ ) {
25724
25725 const texture = textures[ i ];
25726 renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer();
25727
25728 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25729
25730 const glFormat = utils.convert( texture.format, texture.colorSpace );
25731 const glType = utils.convert( texture.type );
25732 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
25734 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
25735
25736 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25737
25738 }
25739
25740 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
25741
25742 if ( renderTarget.depthBuffer ) {
25743
25744 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
25745 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
25746
25747 }
25748
25749 state.bindFramebuffer( _gl.FRAMEBUFFER, null );
25750
25751 }
25752
25753 }
25754
25755 // Setup color buffer
25756
25757 if ( isCube ) {
25758
25759 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
25760 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
25761
25762 for ( let i = 0; i < 6; i ++ ) {
25763
25764 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25765
25766 for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25767
25768 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );
25769
25770 }
25771
25772 } else {
25773
25774 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 );
25775
25776 }
25777
25778 }
25779
25781
25782 generateMipmap( _gl.TEXTURE_CUBE_MAP );
25783
25784 }
25785
25786 state.unbindTexture();
25787
25788 } else if ( isMultipleRenderTargets ) {
25789
25790 const textures = renderTarget.texture;
25791
25792 for ( let i = 0, il = textures.length; i < il; i ++ ) {
25793
25794 const attachment = textures[ i ];
25795 const attachmentProperties = properties.get( attachment );
25796
25797 state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );
25799 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );
25800
25802
25803 generateMipmap( _gl.TEXTURE_2D );
25804
25805 }
25806
25807 }
25808
25809 state.unbindTexture();
25810
25811 } else {
25812
25813 let glTextureType = _gl.TEXTURE_2D;
25814
25815 if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {
25816
25817 if ( isWebGL2 ) {
25818
25819 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;
25820
25821 } else {
25822
25823 console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' );
25824
25825 }
25826
25827 }
25828
25829 state.bindTexture( glTextureType, textureProperties.__webglTexture );
25831
25832 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) {
25833
25834 for ( let level = 0; level < texture.mipmaps.length; level ++ ) {
25835
25836 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level );
25837
25838 }
25839
25840 } else {
25841
25842 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );
25843
25844 }
25845
25847
25849
25850 }
25851
25852 state.unbindTexture();
25853
25854 }
25855
25856 // Setup depth and stencil buffers
25857
25858 if ( renderTarget.depthBuffer ) {
25859
25861
25862 }
25863
25864 }
25865
25867
25869
25870 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
25871
25872 for ( let i = 0, il = textures.length; i < il; i ++ ) {
25873
25874 const texture = textures[ i ];
25875
25877
25878 const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
25879 const webglTexture = properties.get( texture ).__webglTexture;
25880
25881 state.bindTexture( target, webglTexture );
25883 state.unbindTexture();
25884
25885 }
25886
25887 }
25888
25889 }
25890
25892
25893 if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
25894
25895 const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ];
25896 const width = renderTarget.width;
25897 const height = renderTarget.height;
25898 let mask = _gl.COLOR_BUFFER_BIT;
25899 const invalidationArray = [];
25900 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
25901 const renderTargetProperties = properties.get( renderTarget );
25902 const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
25903
25904 // If MRT we need to remove FBO attachments
25906
25907 for ( let i = 0; i < textures.length; i ++ ) {
25908
25909 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25910 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );
25911
25912 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25913 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );
25914
25915 }
25916
25917 }
25918
25919 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25920 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25921
25922 for ( let i = 0; i < textures.length; i ++ ) {
25923
25924 invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i );
25925
25926 if ( renderTarget.depthBuffer ) {
25927
25929
25930 }
25931
25932 const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false;
25933
25934 if ( ignoreDepthValues === false ) {
25935
25936 if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
25937 if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
25938
25939 }
25940
25942
25943 _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25944
25945 }
25946
25947 if ( ignoreDepthValues === true ) {
25948
25949 _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] );
25950 _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
25951
25952 }
25953
25955
25956 const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25957 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );
25958
25959 }
25960
25961 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
25962
25964
25965 _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray );
25966
25967 }
25968
25969
25970 }
25971
25972 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
25973 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );
25974
25975 // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments
25977
25978 for ( let i = 0; i < textures.length; i ++ ) {
25979
25980 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25981 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );
25982
25983 const webglTexture = properties.get( textures[ i ] ).__webglTexture;
25984
25985 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
25986 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );
25987
25988 }
25989
25990 }
25991
25992 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
25993
25994 }
25995
25996 }
25997
25999
26000 return Math.min( capabilities.maxSamples, renderTarget.samples );
26001
26002 }
26003
26004 function useMultisampledRTT( renderTarget ) {
26005
26006 const renderTargetProperties = properties.get( renderTarget );
26007
26008 return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;
26009
26010 }
26011
26012 function updateVideoTexture( texture ) {
26013
26014 const frame = info.render.frame;
26015
26016 // Check the last frame we updated the VideoTexture
26017
26018 if ( _videoTextures.get( texture ) !== frame ) {
26019
26021 texture.update();
26022
26023 }
26024
26025 }
26026
26027 function verifyColorSpace( texture, image ) {
26028
26029 const colorSpace = texture.colorSpace;
26030 const format = texture.format;
26031 const type = texture.type;
26032
26033 if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
26034
26036
26037 // sRGB
26038
26039 if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {
26040
26041 if ( isWebGL2 === false ) {
26042
26043 // in WebGL 1, try to use EXT_sRGB extension and unsized formats
26044
26045 if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) {
26046
26047 texture.format = _SRGBAFormat;
26048
26049 // it's not possible to generate mips in WebGL 1 with this extension
26050
26051 texture.minFilter = LinearFilter;
26052 texture.generateMipmaps = false;
26053
26054 } else {
26055
26056 // slow fallback (CPU decode)
26057
26058 image = ImageUtils.sRGBToLinear( image );
26059
26060 }
26061
26062 } else {
26063
26064 // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
26065
26066 if ( format !== RGBAFormat || type !== UnsignedByteType ) {
26067
26068 console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );
26069
26070 }
26071
26072 }
26073
26074 } else {
26075
26076 console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );
26077
26078 }
26079
26080 }
26081
26082 return image;
26083
26084 }
26085
26086 //
26087
26090
26102
26103 }
26104
26105 function WebGLUtils( gl, extensions, capabilities ) {
26106
26107 const isWebGL2 = capabilities.isWebGL2;
26108
26109 function convert( p, colorSpace = NoColorSpace ) {
26110
26111 let extension;
26112
26113 const transfer = ColorManagement.getTransfer( colorSpace );
26114
26115 if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
26116 if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
26117 if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
26118
26119 if ( p === ByteType ) return gl.BYTE;
26120 if ( p === ShortType ) return gl.SHORT;
26121 if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
26122 if ( p === IntType ) return gl.INT;
26123 if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
26124 if ( p === FloatType ) return gl.FLOAT;
26125
26126 if ( p === HalfFloatType ) {
26127
26128 if ( isWebGL2 ) return gl.HALF_FLOAT;
26129
26130 extension = extensions.get( 'OES_texture_half_float' );
26131
26132 if ( extension !== null ) {
26133
26134 return extension.HALF_FLOAT_OES;
26135
26136 } else {
26137
26138 return null;
26139
26140 }
26141
26142 }
26143
26144 if ( p === AlphaFormat ) return gl.ALPHA;
26145 if ( p === RGBAFormat ) return gl.RGBA;
26146 if ( p === LuminanceFormat ) return gl.LUMINANCE;
26147 if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
26148 if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
26149 if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
26150
26151 // WebGL 1 sRGB fallback
26152
26153 if ( p === _SRGBAFormat ) {
26154
26155 extension = extensions.get( 'EXT_sRGB' );
26156
26157 if ( extension !== null ) {
26158
26159 return extension.SRGB_ALPHA_EXT;
26160
26161 } else {
26162
26163 return null;
26164
26165 }
26166
26167 }
26168
26169 // WebGL2 formats.
26170
26171 if ( p === RedFormat ) return gl.RED;
26172 if ( p === RedIntegerFormat ) return gl.RED_INTEGER;
26173 if ( p === RGFormat ) return gl.RG;
26174 if ( p === RGIntegerFormat ) return gl.RG_INTEGER;
26175 if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;
26176
26177 // S3TC
26178
26180
26181 if ( transfer === SRGBTransfer ) {
26182
26183 extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
26184
26185 if ( extension !== null ) {
26186
26187 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
26188 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
26189 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
26190 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
26191
26192 } else {
26193
26194 return null;
26195
26196 }
26197
26198 } else {
26199
26200 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
26201
26202 if ( extension !== null ) {
26203
26204 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
26205 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
26206 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
26207 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
26208
26209 } else {
26210
26211 return null;
26212
26213 }
26214
26215 }
26216
26217 }
26218
26219 // PVRTC
26220
26222
26223 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
26224
26225 if ( extension !== null ) {
26226
26227 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
26228 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
26229 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
26230 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
26231
26232 } else {
26233
26234 return null;
26235
26236 }
26237
26238 }
26239
26240 // ETC1
26241
26242 if ( p === RGB_ETC1_Format ) {
26243
26244 extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
26245
26246 if ( extension !== null ) {
26247
26248 return extension.COMPRESSED_RGB_ETC1_WEBGL;
26249
26250 } else {
26251
26252 return null;
26253
26254 }
26255
26256 }
26257
26258 // ETC2
26259
26260 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {
26261
26262 extension = extensions.get( 'WEBGL_compressed_texture_etc' );
26263
26264 if ( extension !== null ) {
26265
26266 if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
26267 if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
26268
26269 } else {
26270
26271 return null;
26272
26273 }
26274
26275 }
26276
26277 // ASTC
26278
26284
26285 extension = extensions.get( 'WEBGL_compressed_texture_astc' );
26286
26287 if ( extension !== null ) {
26288
26289 if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
26290 if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
26291 if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
26292 if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
26293 if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
26294 if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
26295 if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
26296 if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
26297 if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
26298 if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
26299 if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
26300 if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
26301 if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
26302 if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
26303
26304 } else {
26305
26306 return null;
26307
26308 }
26309
26310 }
26311
26312 // BPTC
26313
26315
26316 extension = extensions.get( 'EXT_texture_compression_bptc' );
26317
26318 if ( extension !== null ) {
26319
26320 if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
26321 if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
26322 if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
26323
26324 } else {
26325
26326 return null;
26327
26328 }
26329
26330 }
26331
26332 // RGTC
26333
26335
26336 extension = extensions.get( 'EXT_texture_compression_rgtc' );
26337
26338 if ( extension !== null ) {
26339
26340 if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;
26341 if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;
26342 if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;
26343 if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
26344
26345 } else {
26346
26347 return null;
26348
26349 }
26350
26351 }
26352
26353 //
26354
26355 if ( p === UnsignedInt248Type ) {
26356
26357 if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8;
26358
26359 extension = extensions.get( 'WEBGL_depth_texture' );
26360
26361 if ( extension !== null ) {
26362
26363 return extension.UNSIGNED_INT_24_8_WEBGL;
26364
26365 } else {
26366
26367 return null;
26368
26369 }
26370
26371 }
26372
26373 // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)
26374
26375 return ( gl[ p ] !== undefined ) ? gl[ p ] : null;
26376
26377 }
26378
26379 return { convert: convert };
26380
26381 }
26382
26383 class ArrayCamera extends PerspectiveCamera {
26384
26385 constructor( array = [] ) {
26386
26387 super();
26388
26389 this.isArrayCamera = true;
26390
26391 this.cameras = array;
26392
26393 }
26394
26395 }
26396
26397 class Group extends Object3D {
26398
26399 constructor() {
26400
26401 super();
26402
26403 this.isGroup = true;
26404
26405 this.type = 'Group';
26406
26407 }
26408
26409 }
26410
26411 const _moveEvent = { type: 'move' };
26412
26413 class WebXRController {
26414
26415 constructor() {
26416
26417 this._targetRay = null;
26418 this._grip = null;
26419 this._hand = null;
26420
26421 }
26422
26423 getHandSpace() {
26424
26425 if ( this._hand === null ) {
26426
26427 this._hand = new Group();
26428 this._hand.matrixAutoUpdate = false;
26429 this._hand.visible = false;
26430
26431 this._hand.joints = {};
26432 this._hand.inputState = { pinching: false };
26433
26434 }
26435
26436 return this._hand;
26437
26438 }
26439
26441
26442 if ( this._targetRay === null ) {
26443
26444 this._targetRay = new Group();
26445 this._targetRay.matrixAutoUpdate = false;
26446 this._targetRay.visible = false;
26447 this._targetRay.hasLinearVelocity = false;
26448 this._targetRay.linearVelocity = new Vector3();
26449 this._targetRay.hasAngularVelocity = false;
26450 this._targetRay.angularVelocity = new Vector3();
26451
26452 }
26453
26454 return this._targetRay;
26455
26456 }
26457
26458 getGripSpace() {
26459
26460 if ( this._grip === null ) {
26461
26462 this._grip = new Group();
26463 this._grip.matrixAutoUpdate = false;
26464 this._grip.visible = false;
26465 this._grip.hasLinearVelocity = false;
26466 this._grip.linearVelocity = new Vector3();
26467 this._grip.hasAngularVelocity = false;
26468 this._grip.angularVelocity = new Vector3();
26469
26470 }
26471
26472 return this._grip;
26473
26474 }
26475
26476 dispatchEvent( event ) {
26477
26478 if ( this._targetRay !== null ) {
26479
26480 this._targetRay.dispatchEvent( event );
26481
26482 }
26483
26484 if ( this._grip !== null ) {
26485
26486 this._grip.dispatchEvent( event );
26487
26488 }
26489
26490 if ( this._hand !== null ) {
26491
26492 this._hand.dispatchEvent( event );
26493
26494 }
26495
26496 return this;
26497
26498 }
26499
26500 connect( inputSource ) {
26501
26502 if ( inputSource && inputSource.hand ) {
26503
26504 const hand = this._hand;
26505
26506 if ( hand ) {
26507
26508 for ( const inputjoint of inputSource.hand.values() ) {
26509
26510 // Initialize hand with joints when connected
26511 this._getHandJoint( hand, inputjoint );
26512
26513 }
26514
26515 }
26516
26517 }
26518
26519 this.dispatchEvent( { type: 'connected', data: inputSource } );
26520
26521 return this;
26522
26523 }
26524
26526
26527 this.dispatchEvent( { type: 'disconnected', data: inputSource } );
26528
26529 if ( this._targetRay !== null ) {
26530
26531 this._targetRay.visible = false;
26532
26533 }
26534
26535 if ( this._grip !== null ) {
26536
26537 this._grip.visible = false;
26538
26539 }
26540
26541 if ( this._hand !== null ) {
26542
26543 this._hand.visible = false;
26544
26545 }
26546
26547 return this;
26548
26549 }
26550
26552
26553 let inputPose = null;
26554 let gripPose = null;
26555 let handPose = null;
26556
26557 const targetRay = this._targetRay;
26558 const grip = this._grip;
26559 const hand = this._hand;
26560
26561 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {
26562
26563 if ( hand && inputSource.hand ) {
26564
26565 handPose = true;
26566
26567 for ( const inputjoint of inputSource.hand.values() ) {
26568
26569 // Update the joints groups with the XRJoint poses
26570 const jointPose = frame.getJointPose( inputjoint, referenceSpace );
26571
26572 // The transform of this joint will be updated with the joint pose on each frame
26573 const joint = this._getHandJoint( hand, inputjoint );
26574
26575 if ( jointPose !== null ) {
26576
26577 joint.matrix.fromArray( jointPose.transform.matrix );
26578 joint.matrix.decompose( joint.position, joint.rotation, joint.scale );
26579 joint.matrixWorldNeedsUpdate = true;
26580 joint.jointRadius = jointPose.radius;
26581
26582 }
26583
26584 joint.visible = jointPose !== null;
26585
26586 }
26587
26588 // Custom events
26589
26590 // Check pinchz
26591 const indexTip = hand.joints[ 'index-finger-tip' ];
26592 const thumbTip = hand.joints[ 'thumb-tip' ];
26593 const distance = indexTip.position.distanceTo( thumbTip.position );
26594
26595 const distanceToPinch = 0.02;
26596 const threshold = 0.005;
26597
26598 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {
26599
26600 hand.inputState.pinching = false;
26601 this.dispatchEvent( {
26602 type: 'pinchend',
26603 handedness: inputSource.handedness,
26604 target: this
26605 } );
26606
26607 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {
26608
26609 hand.inputState.pinching = true;
26610 this.dispatchEvent( {
26611 type: 'pinchstart',
26612 handedness: inputSource.handedness,
26613 target: this
26614 } );
26615
26616 }
26617
26618 } else {
26619
26620 if ( grip !== null && inputSource.gripSpace ) {
26621
26622 gripPose = frame.getPose( inputSource.gripSpace, referenceSpace );
26623
26624 if ( gripPose !== null ) {
26625
26626 grip.matrix.fromArray( gripPose.transform.matrix );
26627 grip.matrix.decompose( grip.position, grip.rotation, grip.scale );
26628 grip.matrixWorldNeedsUpdate = true;
26629
26630 if ( gripPose.linearVelocity ) {
26631
26632 grip.hasLinearVelocity = true;
26633 grip.linearVelocity.copy( gripPose.linearVelocity );
26634
26635 } else {
26636
26637 grip.hasLinearVelocity = false;
26638
26639 }
26640
26641 if ( gripPose.angularVelocity ) {
26642
26643 grip.hasAngularVelocity = true;
26644 grip.angularVelocity.copy( gripPose.angularVelocity );
26645
26646 } else {
26647
26648 grip.hasAngularVelocity = false;
26649
26650 }
26651
26652 }
26653
26654 }
26655
26656 }
26657
26658 if ( targetRay !== null ) {
26659
26660 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
26661
26662 // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it
26663 if ( inputPose === null && gripPose !== null ) {
26664
26666
26667 }
26668
26669 if ( inputPose !== null ) {
26670
26671 targetRay.matrix.fromArray( inputPose.transform.matrix );
26672 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );
26673 targetRay.matrixWorldNeedsUpdate = true;
26674
26675 if ( inputPose.linearVelocity ) {
26676
26677 targetRay.hasLinearVelocity = true;
26678 targetRay.linearVelocity.copy( inputPose.linearVelocity );
26679
26680 } else {
26681
26682 targetRay.hasLinearVelocity = false;
26683
26684 }
26685
26686 if ( inputPose.angularVelocity ) {
26687
26688 targetRay.hasAngularVelocity = true;
26689 targetRay.angularVelocity.copy( inputPose.angularVelocity );
26690
26691 } else {
26692
26693 targetRay.hasAngularVelocity = false;
26694
26695 }
26696
26697 this.dispatchEvent( _moveEvent );
26698
26699 }
26700
26701 }
26702
26703
26704 }
26705
26706 if ( targetRay !== null ) {
26707
26708 targetRay.visible = ( inputPose !== null );
26709
26710 }
26711
26712 if ( grip !== null ) {
26713
26714 grip.visible = ( gripPose !== null );
26715
26716 }
26717
26718 if ( hand !== null ) {
26719
26720 hand.visible = ( handPose !== null );
26721
26722 }
26723
26724 return this;
26725
26726 }
26727
26728 // private method
26729
26731
26732 if ( hand.joints[ inputjoint.jointName ] === undefined ) {
26733
26734 const joint = new Group();
26735 joint.matrixAutoUpdate = false;
26736 joint.visible = false;
26737 hand.joints[ inputjoint.jointName ] = joint;
26738
26739 hand.add( joint );
26740
26741 }
26742
26743 return hand.joints[ inputjoint.jointName ];
26744
26745 }
26746
26747 }
26748
26749 class WebXRManager extends EventDispatcher {
26750
26751 constructor( renderer, gl ) {
26752
26753 super();
26754
26755 const scope = this;
26756
26757 let session = null;
26758
26760
26761 let referenceSpace = null;
26762 let referenceSpaceType = 'local-floor';
26763 // Set default foveation to maximum.
26764 let foveation = 1.0;
26766
26767 let pose = null;
26768 let glBinding = null;
26769 let glProjLayer = null;
26770 let glBaseLayer = null;
26771 let xrFrame = null;
26772 const attributes = gl.getContextAttributes();
26773 let initialRenderTarget = null;
26774 let newRenderTarget = null;
26775
26776 const controllers = [];
26777 const controllerInputSources = [];
26778
26779 const currentSize = new Vector2();
26780 let currentPixelRatio = null;
26781
26782 //
26783
26784 const cameraL = new PerspectiveCamera();
26785 cameraL.layers.enable( 1 );
26786 cameraL.viewport = new Vector4();
26787
26788 const cameraR = new PerspectiveCamera();
26789 cameraR.layers.enable( 2 );
26790 cameraR.viewport = new Vector4();
26791
26792 const cameras = [ cameraL, cameraR ];
26793
26794 const cameraXR = new ArrayCamera();
26795 cameraXR.layers.enable( 1 );
26796 cameraXR.layers.enable( 2 );
26797
26798 let _currentDepthNear = null;
26799 let _currentDepthFar = null;
26800
26801 //
26802
26803 this.cameraAutoUpdate = true;
26804 this.enabled = false;
26805
26806 this.isPresenting = false;
26807
26808 this.getController = function ( index ) {
26809
26811
26812 if ( controller === undefined ) {
26813
26816
26817 }
26818
26819 return controller.getTargetRaySpace();
26820
26821 };
26822
26823 this.getControllerGrip = function ( index ) {
26824
26825 let controller = controllers[ index ];
26826
26827 if ( controller === undefined ) {
26828
26831
26832 }
26833
26834 return controller.getGripSpace();
26835
26836 };
26837
26838 this.getHand = function ( index ) {
26839
26840 let controller = controllers[ index ];
26841
26842 if ( controller === undefined ) {
26843
26846
26847 }
26848
26849 return controller.getHandSpace();
26850
26851 };
26852
26853 //
26854
26855 function onSessionEvent( event ) {
26856
26857 const controllerIndex = controllerInputSources.indexOf( event.inputSource );
26858
26859 if ( controllerIndex === - 1 ) {
26860
26861 return;
26862
26863 }
26864
26866
26867 if ( controller !== undefined ) {
26868
26869 controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );
26870 controller.dispatchEvent( { type: event.type, data: event.inputSource } );
26871
26872 }
26873
26874 }
26875
26876 function onSessionEnd() {
26877
26878 session.removeEventListener( 'select', onSessionEvent );
26879 session.removeEventListener( 'selectstart', onSessionEvent );
26880 session.removeEventListener( 'selectend', onSessionEvent );
26881 session.removeEventListener( 'squeeze', onSessionEvent );
26882 session.removeEventListener( 'squeezestart', onSessionEvent );
26883 session.removeEventListener( 'squeezeend', onSessionEvent );
26884 session.removeEventListener( 'end', onSessionEnd );
26885 session.removeEventListener( 'inputsourceschange', onInputSourcesChange );
26886
26887 for ( let i = 0; i < controllers.length; i ++ ) {
26888
26890
26891 if ( inputSource === null ) continue;
26892
26893 controllerInputSources[ i ] = null;
26894
26895 controllers[ i ].disconnect( inputSource );
26896
26897 }
26898
26899 _currentDepthNear = null;
26900 _currentDepthFar = null;
26901
26902 // restore framebuffer/rendering state
26903
26904 renderer.setRenderTarget( initialRenderTarget );
26905
26906 glBaseLayer = null;
26907 glProjLayer = null;
26908 glBinding = null;
26909 session = null;
26910 newRenderTarget = null;
26911
26912 //
26913
26914 animation.stop();
26915
26916 scope.isPresenting = false;
26917
26918 renderer.setPixelRatio( currentPixelRatio );
26919 renderer.setSize( currentSize.width, currentSize.height, false );
26920
26921 scope.dispatchEvent( { type: 'sessionend' } );
26922
26923 }
26924
26925 this.setFramebufferScaleFactor = function ( value ) {
26926
26928
26929 if ( scope.isPresenting === true ) {
26930
26931 console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );
26932
26933 }
26934
26935 };
26936
26937 this.setReferenceSpaceType = function ( value ) {
26938
26940
26941 if ( scope.isPresenting === true ) {
26942
26943 console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );
26944
26945 }
26946
26947 };
26948
26949 this.getReferenceSpace = function () {
26950
26951 return customReferenceSpace || referenceSpace;
26952
26953 };
26954
26955 this.setReferenceSpace = function ( space ) {
26956
26957 customReferenceSpace = space;
26958
26959 };
26960
26961 this.getBaseLayer = function () {
26962
26963 return glProjLayer !== null ? glProjLayer : glBaseLayer;
26964
26965 };
26966
26967 this.getBinding = function () {
26968
26969 return glBinding;
26970
26971 };
26972
26973 this.getFrame = function () {
26974
26975 return xrFrame;
26976
26977 };
26978
26979 this.getSession = function () {
26980
26981 return session;
26982
26983 };
26984
26985 this.setSession = async function ( value ) {
26986
26987 session = value;
26988
26989 if ( session !== null ) {
26990
26991 initialRenderTarget = renderer.getRenderTarget();
26992
26993 session.addEventListener( 'select', onSessionEvent );
26994 session.addEventListener( 'selectstart', onSessionEvent );
26995 session.addEventListener( 'selectend', onSessionEvent );
26996 session.addEventListener( 'squeeze', onSessionEvent );
26997 session.addEventListener( 'squeezestart', onSessionEvent );
26998 session.addEventListener( 'squeezeend', onSessionEvent );
26999 session.addEventListener( 'end', onSessionEnd );
27000 session.addEventListener( 'inputsourceschange', onInputSourcesChange );
27001
27002 if ( attributes.xrCompatible !== true ) {
27003
27004 await gl.makeXRCompatible();
27005
27006 }
27007
27008 currentPixelRatio = renderer.getPixelRatio();
27009 renderer.getSize( currentSize );
27010
27011 if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) {
27012
27013 const layerInit = {
27014 antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true,
27015 alpha: true,
27019 };
27020
27022
27023 session.updateRenderState( { baseLayer: glBaseLayer } );
27024
27025 renderer.setPixelRatio( 1 );
27026 renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );
27027
27029 glBaseLayer.framebufferWidth,
27030 glBaseLayer.framebufferHeight,
27031 {
27032 format: RGBAFormat,
27033 type: UnsignedByteType,
27034 colorSpace: renderer.outputColorSpace,
27035 stencilBuffer: attributes.stencil
27036 }
27037 );
27038
27039 } else {
27040
27041 let depthFormat = null;
27042 let depthType = null;
27043 let glDepthFormat = null;
27044
27045 if ( attributes.depth ) {
27046
27047 glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
27050
27051 }
27052
27053 const projectionlayerInit = {
27054 colorFormat: gl.RGBA8,
27057 };
27058
27060
27061 glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
27062
27063 session.updateRenderState( { layers: [ glProjLayer ] } );
27064
27065 renderer.setPixelRatio( 1 );
27066 renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );
27067
27069 glProjLayer.textureWidth,
27070 glProjLayer.textureHeight,
27071 {
27072 format: RGBAFormat,
27073 type: UnsignedByteType,
27074 depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
27075 stencilBuffer: attributes.stencil,
27076 colorSpace: renderer.outputColorSpace,
27077 samples: attributes.antialias ? 4 : 0
27078 } );
27079
27080 const renderTargetProperties = renderer.properties.get( newRenderTarget );
27081 renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues;
27082
27083 }
27084
27085 newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278
27086
27087 this.setFoveation( foveation );
27088
27089 customReferenceSpace = null;
27090 referenceSpace = await session.requestReferenceSpace( referenceSpaceType );
27091
27092 animation.setContext( session );
27093 animation.start();
27094
27095 scope.isPresenting = true;
27096
27097 scope.dispatchEvent( { type: 'sessionstart' } );
27098
27099 }
27100
27101 };
27102
27103 this.getEnvironmentBlendMode = function () {
27104
27105 if ( session !== null ) {
27106
27107 return session.environmentBlendMode;
27108
27109 }
27110
27111 };
27112
27113 function onInputSourcesChange( event ) {
27114
27115 // Notify disconnected
27116
27117 for ( let i = 0; i < event.removed.length; i ++ ) {
27118
27119 const inputSource = event.removed[ i ];
27120 const index = controllerInputSources.indexOf( inputSource );
27121
27122 if ( index >= 0 ) {
27123
27124 controllerInputSources[ index ] = null;
27125 controllers[ index ].disconnect( inputSource );
27126
27127 }
27128
27129 }
27130
27131 // Notify connected
27132
27133 for ( let i = 0; i < event.added.length; i ++ ) {
27134
27135 const inputSource = event.added[ i ];
27136
27138
27139 if ( controllerIndex === - 1 ) {
27140
27141 // Assign input source a controller that currently has no input source
27142
27143 for ( let i = 0; i < controllers.length; i ++ ) {
27144
27145 if ( i >= controllerInputSources.length ) {
27146
27149 break;
27150
27151 } else if ( controllerInputSources[ i ] === null ) {
27152
27155 break;
27156
27157 }
27158
27159 }
27160
27161 // If all controllers do currently receive input we ignore new ones
27162
27163 if ( controllerIndex === - 1 ) break;
27164
27165 }
27166
27168
27169 if ( controller ) {
27170
27171 controller.connect( inputSource );
27172
27173 }
27174
27175 }
27176
27177 }
27178
27179 //
27180
27181 const cameraLPos = new Vector3();
27182 const cameraRPos = new Vector3();
27183
27191
27192 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
27193 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
27194
27195 const ipd = cameraLPos.distanceTo( cameraRPos );
27196
27197 const projL = cameraL.projectionMatrix.elements;
27198 const projR = cameraR.projectionMatrix.elements;
27199
27200 // VR systems will have identical far and near planes, and
27201 // most likely identical top and bottom frustum extents.
27202 // Use the left camera for these values.
27203 const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
27204 const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
27205 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
27206 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
27207
27208 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
27209 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
27210 const left = near * leftFov;
27211 const right = near * rightFov;
27212
27213 // Calculate the new camera's position offset from the
27214 // left camera. xOffset should be roughly half `ipd`.
27215 const zOffset = ipd / ( - leftFov + rightFov );
27216 const xOffset = zOffset * - leftFov;
27217
27218 // TODO: Better way to apply this offset?
27219 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
27220 camera.translateX( xOffset );
27221 camera.translateZ( zOffset );
27222 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
27223 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27224
27225 // Find the union of the frustum values of the cameras and scale
27226 // the values so that the near plane's position does not change in world space,
27227 // although must now be relative to the new union camera.
27228 const near2 = near + zOffset;
27229 const far2 = far + zOffset;
27230 const left2 = left - xOffset;
27231 const right2 = right + ( ipd - xOffset );
27232 const top2 = topFov * far / far2 * near2;
27233 const bottom2 = bottomFov * far / far2 * near2;
27234
27235 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
27236 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27237
27238 }
27239
27240 function updateCamera( camera, parent ) {
27241
27242 if ( parent === null ) {
27243
27244 camera.matrixWorld.copy( camera.matrix );
27245
27246 } else {
27247
27248 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
27249
27250 }
27251
27252 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
27253
27254 }
27255
27256 this.updateCamera = function ( camera ) {
27257
27258 if ( session === null ) return;
27259
27260 cameraXR.near = cameraR.near = cameraL.near = camera.near;
27261 cameraXR.far = cameraR.far = cameraL.far = camera.far;
27262
27263 if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {
27264
27265 // Note that the new renderState won't apply until the next frame. See #18320
27266
27267 session.updateRenderState( {
27268 depthNear: cameraXR.near,
27269 depthFar: cameraXR.far
27270 } );
27271
27274
27275 }
27276
27277 const parent = camera.parent;
27278 const cameras = cameraXR.cameras;
27279
27281
27282 for ( let i = 0; i < cameras.length; i ++ ) {
27283
27285
27286 }
27287
27288 // update projection matrix for proper view frustum culling
27289
27290 if ( cameras.length === 2 ) {
27291
27293
27294 } else {
27295
27296 // assume single camera setup (AR)
27297
27298 cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );
27299
27300 }
27301
27302 // update user camera and its children
27303
27305
27306 };
27307
27308 function updateUserCamera( camera, cameraXR, parent ) {
27309
27310 if ( parent === null ) {
27311
27312 camera.matrix.copy( cameraXR.matrixWorld );
27313
27314 } else {
27315
27316 camera.matrix.copy( parent.matrixWorld );
27317 camera.matrix.invert();
27318 camera.matrix.multiply( cameraXR.matrixWorld );
27319
27320 }
27321
27322 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27323 camera.updateMatrixWorld( true );
27324
27325 camera.projectionMatrix.copy( cameraXR.projectionMatrix );
27326 camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
27327
27328 if ( camera.isPerspectiveCamera ) {
27329
27330 camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
27331 camera.zoom = 1;
27332
27333 }
27334
27335 }
27336
27337 this.getCamera = function () {
27338
27339 return cameraXR;
27340
27341 };
27342
27343 this.getFoveation = function () {
27344
27345 if ( glProjLayer === null && glBaseLayer === null ) {
27346
27347 return undefined;
27348
27349 }
27350
27351 return foveation;
27352
27353 };
27354
27355 this.setFoveation = function ( value ) {
27356
27357 // 0 = no foveation = full resolution
27358 // 1 = maximum foveation = the edges render at lower resolution
27359
27360 foveation = value;
27361
27362 if ( glProjLayer !== null ) {
27363
27364 glProjLayer.fixedFoveation = value;
27365
27366 }
27367
27368 if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {
27369
27370 glBaseLayer.fixedFoveation = value;
27371
27372 }
27373
27374 };
27375
27376 // Animation Loop
27377
27379
27380 function onAnimationFrame( time, frame ) {
27381
27382 pose = frame.getViewerPose( customReferenceSpace || referenceSpace );
27383 xrFrame = frame;
27384
27385 if ( pose !== null ) {
27386
27387 const views = pose.views;
27388
27389 if ( glBaseLayer !== null ) {
27390
27391 renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
27392 renderer.setRenderTarget( newRenderTarget );
27393
27394 }
27395
27396 let cameraXRNeedsUpdate = false;
27397
27398 // check if it's necessary to rebuild cameraXR's camera list
27399
27400 if ( views.length !== cameraXR.cameras.length ) {
27401
27402 cameraXR.cameras.length = 0;
27403 cameraXRNeedsUpdate = true;
27404
27405 }
27406
27407 for ( let i = 0; i < views.length; i ++ ) {
27408
27409 const view = views[ i ];
27410
27411 let viewport = null;
27412
27413 if ( glBaseLayer !== null ) {
27414
27415 viewport = glBaseLayer.getViewport( view );
27416
27417 } else {
27418
27419 const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
27420 viewport = glSubImage.viewport;
27421
27422 // For side-by-side projection, we only produce a single texture for both eyes.
27423 if ( i === 0 ) {
27424
27425 renderer.setRenderTargetTextures(
27427 glSubImage.colorTexture,
27428 glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );
27429
27430 renderer.setRenderTarget( newRenderTarget );
27431
27432 }
27433
27434 }
27435
27436 let camera = cameras[ i ];
27437
27438 if ( camera === undefined ) {
27439
27440 camera = new PerspectiveCamera();
27441 camera.layers.enable( i );
27442 camera.viewport = new Vector4();
27443 cameras[ i ] = camera;
27444
27445 }
27446
27447 camera.matrix.fromArray( view.transform.matrix );
27448 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
27449 camera.projectionMatrix.fromArray( view.projectionMatrix );
27450 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
27451 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
27452
27453 if ( i === 0 ) {
27454
27455 cameraXR.matrix.copy( camera.matrix );
27456 cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );
27457
27458 }
27459
27460 if ( cameraXRNeedsUpdate === true ) {
27461
27462 cameraXR.cameras.push( camera );
27463
27464 }
27465
27466 }
27467
27468 }
27469
27470 //
27471
27472 for ( let i = 0; i < controllers.length; i ++ ) {
27473
27475 const controller = controllers[ i ];
27476
27477 if ( inputSource !== null && controller !== undefined ) {
27478
27480
27481 }
27482
27483 }
27484
27486
27487 if ( frame.detectedPlanes ) {
27488
27489 scope.dispatchEvent( { type: 'planesdetected', data: frame } );
27490
27491 }
27492
27493 xrFrame = null;
27494
27495 }
27496
27497 const animation = new WebGLAnimation();
27498
27499 animation.setAnimationLoop( onAnimationFrame );
27500
27501 this.setAnimationLoop = function ( callback ) {
27502
27503 onAnimationFrameCallback = callback;
27504
27505 };
27506
27507 this.dispose = function () {};
27508
27509 }
27510
27511 }
27512
27513 function WebGLMaterials( renderer, properties ) {
27514
27515 function refreshTransformUniform( map, uniform ) {
27516
27517 if ( map.matrixAutoUpdate === true ) {
27518
27519 map.updateMatrix();
27520
27521 }
27522
27523 uniform.value.copy( map.matrix );
27524
27525 }
27526
27527 function refreshFogUniforms( uniforms, fog ) {
27528
27529 fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );
27530
27531 if ( fog.isFog ) {
27532
27533 uniforms.fogNear.value = fog.near;
27534 uniforms.fogFar.value = fog.far;
27535
27536 } else if ( fog.isFogExp2 ) {
27537
27538 uniforms.fogDensity.value = fog.density;
27539
27540 }
27541
27542 }
27543
27545
27546 if ( material.isMeshBasicMaterial ) {
27547
27549
27550 } else if ( material.isMeshLambertMaterial ) {
27551
27553
27554 } else if ( material.isMeshToonMaterial ) {
27555
27558
27559 } else if ( material.isMeshPhongMaterial ) {
27560
27563
27564 } else if ( material.isMeshStandardMaterial ) {
27565
27568
27569 if ( material.isMeshPhysicalMaterial ) {
27570
27572
27573 }
27574
27575 } else if ( material.isMeshMatcapMaterial ) {
27576
27579
27580 } else if ( material.isMeshDepthMaterial ) {
27581
27583
27584 } else if ( material.isMeshDistanceMaterial ) {
27585
27588
27589 } else if ( material.isMeshNormalMaterial ) {
27590
27592
27593 } else if ( material.isLineBasicMaterial ) {
27594
27596
27597 if ( material.isLineDashedMaterial ) {
27598
27600
27601 }
27602
27603 } else if ( material.isPointsMaterial ) {
27604
27606
27607 } else if ( material.isSpriteMaterial ) {
27608
27610
27611 } else if ( material.isShadowMaterial ) {
27612
27613 uniforms.color.value.copy( material.color );
27614 uniforms.opacity.value = material.opacity;
27615
27616 } else if ( material.isShaderMaterial ) {
27617
27618 material.uniformsNeedUpdate = false; // #15581
27619
27620 }
27621
27622 }
27623
27625
27626 uniforms.opacity.value = material.opacity;
27627
27628 if ( material.color ) {
27629
27630 uniforms.diffuse.value.copy( material.color );
27631
27632 }
27633
27634 if ( material.emissive ) {
27635
27636 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
27637
27638 }
27639
27640 if ( material.map ) {
27641
27642 uniforms.map.value = material.map;
27643
27644 refreshTransformUniform( material.map, uniforms.mapTransform );
27645
27646 }
27647
27648 if ( material.alphaMap ) {
27649
27650 uniforms.alphaMap.value = material.alphaMap;
27651
27652 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27653
27654 }
27655
27656 if ( material.bumpMap ) {
27657
27658 uniforms.bumpMap.value = material.bumpMap;
27659
27660 refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform );
27661
27662 uniforms.bumpScale.value = material.bumpScale;
27663
27664 if ( material.side === BackSide ) {
27665
27666 uniforms.bumpScale.value *= - 1;
27667
27668 }
27669
27670 }
27671
27672 if ( material.normalMap ) {
27673
27674 uniforms.normalMap.value = material.normalMap;
27675
27676 refreshTransformUniform( material.normalMap, uniforms.normalMapTransform );
27677
27678 uniforms.normalScale.value.copy( material.normalScale );
27679
27680 if ( material.side === BackSide ) {
27681
27682 uniforms.normalScale.value.negate();
27683
27684 }
27685
27686 }
27687
27688 if ( material.displacementMap ) {
27689
27690 uniforms.displacementMap.value = material.displacementMap;
27691
27692 refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform );
27693
27694 uniforms.displacementScale.value = material.displacementScale;
27695 uniforms.displacementBias.value = material.displacementBias;
27696
27697 }
27698
27699 if ( material.emissiveMap ) {
27700
27701 uniforms.emissiveMap.value = material.emissiveMap;
27702
27703 refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );
27704
27705 }
27706
27707 if ( material.specularMap ) {
27708
27709 uniforms.specularMap.value = material.specularMap;
27710
27711 refreshTransformUniform( material.specularMap, uniforms.specularMapTransform );
27712
27713 }
27714
27715 if ( material.alphaTest > 0 ) {
27716
27717 uniforms.alphaTest.value = material.alphaTest;
27718
27719 }
27720
27721 const envMap = properties.get( material ).envMap;
27722
27723 if ( envMap ) {
27724
27725 uniforms.envMap.value = envMap;
27726
27727 uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
27728
27729 uniforms.reflectivity.value = material.reflectivity;
27730 uniforms.ior.value = material.ior;
27731 uniforms.refractionRatio.value = material.refractionRatio;
27732
27733 }
27734
27735 if ( material.lightMap ) {
27736
27737 uniforms.lightMap.value = material.lightMap;
27738
27739 // artist-friendly light intensity scaling factor
27740 const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1;
27741
27742 uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor;
27743
27744 refreshTransformUniform( material.lightMap, uniforms.lightMapTransform );
27745
27746 }
27747
27748 if ( material.aoMap ) {
27749
27750 uniforms.aoMap.value = material.aoMap;
27751 uniforms.aoMapIntensity.value = material.aoMapIntensity;
27752
27753 refreshTransformUniform( material.aoMap, uniforms.aoMapTransform );
27754
27755 }
27756
27757 }
27758
27760
27761 uniforms.diffuse.value.copy( material.color );
27762 uniforms.opacity.value = material.opacity;
27763
27764 if ( material.map ) {
27765
27766 uniforms.map.value = material.map;
27767
27768 refreshTransformUniform( material.map, uniforms.mapTransform );
27769
27770 }
27771
27772 }
27773
27775
27776 uniforms.dashSize.value = material.dashSize;
27777 uniforms.totalSize.value = material.dashSize + material.gapSize;
27778 uniforms.scale.value = material.scale;
27779
27780 }
27781
27783
27784 uniforms.diffuse.value.copy( material.color );
27785 uniforms.opacity.value = material.opacity;
27786 uniforms.size.value = material.size * pixelRatio;
27787 uniforms.scale.value = height * 0.5;
27788
27789 if ( material.map ) {
27790
27791 uniforms.map.value = material.map;
27792
27793 refreshTransformUniform( material.map, uniforms.uvTransform );
27794
27795 }
27796
27797 if ( material.alphaMap ) {
27798
27799 uniforms.alphaMap.value = material.alphaMap;
27800
27801 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27802
27803 }
27804
27805 if ( material.alphaTest > 0 ) {
27806
27807 uniforms.alphaTest.value = material.alphaTest;
27808
27809 }
27810
27811 }
27812
27814
27815 uniforms.diffuse.value.copy( material.color );
27816 uniforms.opacity.value = material.opacity;
27817 uniforms.rotation.value = material.rotation;
27818
27819 if ( material.map ) {
27820
27821 uniforms.map.value = material.map;
27822
27823 refreshTransformUniform( material.map, uniforms.mapTransform );
27824
27825 }
27826
27827 if ( material.alphaMap ) {
27828
27829 uniforms.alphaMap.value = material.alphaMap;
27830
27831 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );
27832
27833 }
27834
27835 if ( material.alphaTest > 0 ) {
27836
27837 uniforms.alphaTest.value = material.alphaTest;
27838
27839 }
27840
27841 }
27842
27844
27845 uniforms.specular.value.copy( material.specular );
27846 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
27847
27848 }
27849
27851
27852 if ( material.gradientMap ) {
27853
27854 uniforms.gradientMap.value = material.gradientMap;
27855
27856 }
27857
27858 }
27859
27861
27862 uniforms.metalness.value = material.metalness;
27863
27864 if ( material.metalnessMap ) {
27865
27866 uniforms.metalnessMap.value = material.metalnessMap;
27867
27868 refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );
27869
27870 }
27871
27872 uniforms.roughness.value = material.roughness;
27873
27874 if ( material.roughnessMap ) {
27875
27876 uniforms.roughnessMap.value = material.roughnessMap;
27877
27878 refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );
27879
27880 }
27881
27882 const envMap = properties.get( material ).envMap;
27883
27884 if ( envMap ) {
27885
27886 //uniforms.envMap.value = material.envMap; // part of uniforms common
27887 uniforms.envMapIntensity.value = material.envMapIntensity;
27888
27889 }
27890
27891 }
27892
27894
27895 uniforms.ior.value = material.ior; // also part of uniforms common
27896
27897 if ( material.sheen > 0 ) {
27898
27899 uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );
27900
27901 uniforms.sheenRoughness.value = material.sheenRoughness;
27902
27903 if ( material.sheenColorMap ) {
27904
27905 uniforms.sheenColorMap.value = material.sheenColorMap;
27906
27907 refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );
27908
27909 }
27910
27911 if ( material.sheenRoughnessMap ) {
27912
27913 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;
27914
27915 refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );
27916
27917 }
27918
27919 }
27920
27921 if ( material.clearcoat > 0 ) {
27922
27923 uniforms.clearcoat.value = material.clearcoat;
27924 uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
27925
27926 if ( material.clearcoatMap ) {
27927
27928 uniforms.clearcoatMap.value = material.clearcoatMap;
27929
27930 refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );
27931
27932 }
27933
27934 if ( material.clearcoatRoughnessMap ) {
27935
27936 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;
27937
27938 refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );
27939
27940 }
27941
27942 if ( material.clearcoatNormalMap ) {
27943
27944 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
27945
27946 refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );
27947
27948 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
27949
27950 if ( material.side === BackSide ) {
27951
27952 uniforms.clearcoatNormalScale.value.negate();
27953
27954 }
27955
27956 }
27957
27958 }
27959
27960 if ( material.iridescence > 0 ) {
27961
27962 uniforms.iridescence.value = material.iridescence;
27963 uniforms.iridescenceIOR.value = material.iridescenceIOR;
27964 uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];
27965 uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];
27966
27967 if ( material.iridescenceMap ) {
27968
27969 uniforms.iridescenceMap.value = material.iridescenceMap;
27970
27971 refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );
27972
27973 }
27974
27975 if ( material.iridescenceThicknessMap ) {
27976
27977 uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;
27978
27979 refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );
27980
27981 }
27982
27983 }
27984
27985 if ( material.transmission > 0 ) {
27986
27987 uniforms.transmission.value = material.transmission;
27988 uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
27989 uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );
27990
27991 if ( material.transmissionMap ) {
27992
27993 uniforms.transmissionMap.value = material.transmissionMap;
27994
27995 refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );
27996
27997 }
27998
27999 uniforms.thickness.value = material.thickness;
28000
28001 if ( material.thicknessMap ) {
28002
28003 uniforms.thicknessMap.value = material.thicknessMap;
28004
28005 refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );
28006
28007 }
28008
28009 uniforms.attenuationDistance.value = material.attenuationDistance;
28010 uniforms.attenuationColor.value.copy( material.attenuationColor );
28011
28012 }
28013
28014 if ( material.anisotropy > 0 ) {
28015
28016 uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );
28017
28018 if ( material.anisotropyMap ) {
28019
28020 uniforms.anisotropyMap.value = material.anisotropyMap;
28021
28022 refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );
28023
28024 }
28025
28026 }
28027
28028 uniforms.specularIntensity.value = material.specularIntensity;
28029 uniforms.specularColor.value.copy( material.specularColor );
28030
28031 if ( material.specularColorMap ) {
28032
28033 uniforms.specularColorMap.value = material.specularColorMap;
28034
28035 refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );
28036
28037 }
28038
28039 if ( material.specularIntensityMap ) {
28040
28041 uniforms.specularIntensityMap.value = material.specularIntensityMap;
28042
28043 refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );
28044
28045 }
28046
28047 }
28048
28050
28051 if ( material.matcap ) {
28052
28053 uniforms.matcap.value = material.matcap;
28054
28055 }
28056
28057 }
28058
28060
28061 const light = properties.get( material ).light;
28062
28063 uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );
28064 uniforms.nearDistance.value = light.shadow.camera.near;
28065 uniforms.farDistance.value = light.shadow.camera.far;
28066
28067 }
28068
28069 return {
28072 };
28073
28074 }
28075
28077
28078 let buffers = {};
28079 let updateList = {};
28081
28082 const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program
28083
28084 function bind( uniformsGroup, program ) {
28085
28086 const webglProgram = program.program;
28087 state.uniformBlockBinding( uniformsGroup, webglProgram );
28088
28089 }
28090
28091 function update( uniformsGroup, program ) {
28092
28094
28095 if ( buffer === undefined ) {
28096
28098
28101
28102 uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );
28103
28104 }
28105
28106 // ensure to update the binding points/block indices mapping for this program
28107
28108 const webglProgram = program.program;
28109 state.updateUBOMapping( uniformsGroup, webglProgram );
28110
28111 // update UBO once per frame
28112
28113 const frame = info.render.frame;
28114
28115 if ( updateList[ uniformsGroup.id ] !== frame ) {
28116
28118
28120
28121 }
28122
28123 }
28124
28125 function createBuffer( uniformsGroup ) {
28126
28127 // the setup of an UBO is independent of a particular shader program but global
28128
28130 uniformsGroup.__bindingPointIndex = bindingPointIndex;
28131
28132 const buffer = gl.createBuffer();
28133 const size = uniformsGroup.__size;
28134 const usage = uniformsGroup.usage;
28135
28136 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28137 gl.bufferData( gl.UNIFORM_BUFFER, size, usage );
28138 gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28139 gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer );
28140
28141 return buffer;
28142
28143 }
28144
28145 function allocateBindingPointIndex() {
28146
28147 for ( let i = 0; i < maxBindingPoints; i ++ ) {
28148
28149 if ( allocatedBindingPoints.indexOf( i ) === - 1 ) {
28150
28151 allocatedBindingPoints.push( i );
28152 return i;
28153
28154 }
28155
28156 }
28157
28158 console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );
28159
28160 return 0;
28161
28162 }
28163
28164 function updateBufferData( uniformsGroup ) {
28165
28166 const buffer = buffers[ uniformsGroup.id ];
28167 const uniforms = uniformsGroup.uniforms;
28168 const cache = uniformsGroup.__cache;
28169
28170 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );
28171
28172 for ( let i = 0, il = uniforms.length; i < il; i ++ ) {
28173
28174 const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28175
28176 for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28177
28178 const uniform = uniformArray[ j ];
28179
28180 if ( hasUniformChanged( uniform, i, j, cache ) === true ) {
28181
28182 const offset = uniform.__offset;
28183
28184 const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28185
28186 let arrayOffset = 0;
28187
28188 for ( let k = 0; k < values.length; k ++ ) {
28189
28190 const value = values[ k ];
28191
28192 const info = getUniformSize( value );
28193
28194 // TODO add integer and struct support
28195 if ( typeof value === 'number' || typeof value === 'boolean' ) {
28196
28197 uniform.__data[ 0 ] = value;
28198 gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );
28199
28200 } else if ( value.isMatrix3 ) {
28201
28202 // manually converting 3x3 to 3x4
28203
28204 uniform.__data[ 0 ] = value.elements[ 0 ];
28205 uniform.__data[ 1 ] = value.elements[ 1 ];
28206 uniform.__data[ 2 ] = value.elements[ 2 ];
28207 uniform.__data[ 3 ] = 0;
28208 uniform.__data[ 4 ] = value.elements[ 3 ];
28209 uniform.__data[ 5 ] = value.elements[ 4 ];
28210 uniform.__data[ 6 ] = value.elements[ 5 ];
28211 uniform.__data[ 7 ] = 0;
28212 uniform.__data[ 8 ] = value.elements[ 6 ];
28213 uniform.__data[ 9 ] = value.elements[ 7 ];
28214 uniform.__data[ 10 ] = value.elements[ 8 ];
28215 uniform.__data[ 11 ] = 0;
28216
28217 } else {
28218
28219 value.toArray( uniform.__data, arrayOffset );
28220
28221 arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;
28222
28223 }
28224
28225 }
28226
28227 gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );
28228
28229 }
28230
28231 }
28232
28233 }
28234
28235 gl.bindBuffer( gl.UNIFORM_BUFFER, null );
28236
28237 }
28238
28240
28241 const value = uniform.value;
28242 const indexString = index + '_' + indexArray;
28243
28244 if ( cache[ indexString ] === undefined ) {
28245
28246 // cache entry does not exist so far
28247
28248 if ( typeof value === 'number' || typeof value === 'boolean' ) {
28249
28250 cache[ indexString ] = value;
28251
28252 } else {
28253
28254 cache[ indexString ] = value.clone();
28255
28256 }
28257
28258 return true;
28259
28260 } else {
28261
28262 const cachedObject = cache[ indexString ];
28263
28264 // compare current value with cached entry
28265
28266 if ( typeof value === 'number' || typeof value === 'boolean' ) {
28267
28268 if ( cachedObject !== value ) {
28269
28270 cache[ indexString ] = value;
28271 return true;
28272
28273 }
28274
28275 } else {
28276
28277 if ( cachedObject.equals( value ) === false ) {
28278
28279 cachedObject.copy( value );
28280 return true;
28281
28282 }
28283
28284 }
28285
28286 }
28287
28288 return false;
28289
28290 }
28291
28293
28294 // determine total buffer size according to the STD140 layout
28295 // Hint: STD140 is the only supported layout in WebGL 2
28296
28297 const uniforms = uniformsGroup.uniforms;
28298
28299 let offset = 0; // global buffer offset in bytes
28300 const chunkSize = 16; // size of a chunk in bytes
28301
28302 for ( let i = 0, l = uniforms.length; i < l; i ++ ) {
28303
28304 const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];
28305
28306 for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {
28307
28308 const uniform = uniformArray[ j ];
28309
28310 const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];
28311
28312 for ( let k = 0, kl = values.length; k < kl; k ++ ) {
28313
28314 const value = values[ k ];
28315
28316 const info = getUniformSize( value );
28317
28318 // Calculate the chunk offset
28320
28321 // Check for chunk overflow
28322 if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) {
28323
28324 // Add padding and adjust offset
28326
28327 }
28328
28329 // the following two properties will be used for partial buffer updates
28330
28331 uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
28332 uniform.__offset = offset;
28333
28334
28335 // Update the global offset
28336 offset += info.storage;
28337
28338
28339 }
28340
28341 }
28342
28343 }
28344
28345 // ensure correct final padding
28346
28347 const chunkOffset = offset % chunkSize;
28348
28349 if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );
28350
28351 //
28352
28353 uniformsGroup.__size = offset;
28354 uniformsGroup.__cache = {};
28355
28356 return this;
28357
28358 }
28359
28360 function getUniformSize( value ) {
28361
28362 const info = {
28363 boundary: 0, // bytes
28364 storage: 0 // bytes
28365 };
28366
28367 // determine sizes according to STD140
28368
28369 if ( typeof value === 'number' || typeof value === 'boolean' ) {
28370
28371 // float/int/bool
28372
28373 info.boundary = 4;
28374 info.storage = 4;
28375
28376 } else if ( value.isVector2 ) {
28377
28378 // vec2
28379
28380 info.boundary = 8;
28381 info.storage = 8;
28382
28383 } else if ( value.isVector3 || value.isColor ) {
28384
28385 // vec3
28386
28387 info.boundary = 16;
28388 info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes
28389
28390 } else if ( value.isVector4 ) {
28391
28392 // vec4
28393
28394 info.boundary = 16;
28395 info.storage = 16;
28396
28397 } else if ( value.isMatrix3 ) {
28398
28399 // mat3 (in STD140 a 3x3 matrix is represented as 3x4)
28400
28401 info.boundary = 48;
28402 info.storage = 48;
28403
28404 } else if ( value.isMatrix4 ) {
28405
28406 // mat4
28407
28408 info.boundary = 64;
28409 info.storage = 64;
28410
28411 } else if ( value.isTexture ) {
28412
28413 console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' );
28414
28415 } else {
28416
28417 console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value );
28418
28419 }
28420
28421 return info;
28422
28423 }
28424
28425 function onUniformsGroupsDispose( event ) {
28426
28427 const uniformsGroup = event.target;
28428
28429 uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose );
28430
28431 const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );
28432 allocatedBindingPoints.splice( index, 1 );
28433
28434 gl.deleteBuffer( buffers[ uniformsGroup.id ] );
28435
28436 delete buffers[ uniformsGroup.id ];
28437 delete updateList[ uniformsGroup.id ];
28438
28439 }
28440
28441 function dispose() {
28442
28443 for ( const id in buffers ) {
28444
28445 gl.deleteBuffer( buffers[ id ] );
28446
28447 }
28448
28450 buffers = {};
28451 updateList = {};
28452
28453 }
28454
28455 return {
28456
28457 bind: bind,
28458 update: update,
28459
28461
28462 };
28463
28464 }
28465
28466 class WebGLRenderer {
28467
28468 constructor( parameters = {} ) {
28469
28470 const {
28472 context = null,
28473 depth = true,
28474 stencil = true,
28475 alpha = false,
28476 antialias = false,
28477 premultipliedAlpha = true,
28478 preserveDrawingBuffer = false,
28479 powerPreference = 'default',
28481 } = parameters;
28482
28483 this.isWebGLRenderer = true;
28484
28485 let _alpha;
28486
28487 if ( context !== null ) {
28488
28489 _alpha = context.getContextAttributes().alpha;
28490
28491 } else {
28492
28493 _alpha = alpha;
28494
28495 }
28496
28497 const uintClearColor = new Uint32Array( 4 );
28498 const intClearColor = new Int32Array( 4 );
28499
28500 let currentRenderList = null;
28501 let currentRenderState = null;
28502
28503 // render() can be called from within a callback triggered by another render.
28504 // We track this so that the nested render call gets its list and state isolated from the parent render call.
28505
28506 const renderListStack = [];
28507 const renderStateStack = [];
28508
28509 // public properties
28510
28511 this.domElement = canvas;
28512
28513 // Debug configuration container
28514 this.debug = {
28515
28520 checkShaderErrors: true,
28525 onShaderError: null
28526 };
28527
28528 // clearing
28529
28530 this.autoClear = true;
28531 this.autoClearColor = true;
28532 this.autoClearDepth = true;
28533 this.autoClearStencil = true;
28534
28535 // scene graph
28536
28537 this.sortObjects = true;
28538
28539 // user-defined clipping
28540
28541 this.clippingPlanes = [];
28542 this.localClippingEnabled = false;
28543
28544 // physically based shading
28545
28547
28548 // physical lights
28549
28550 this._useLegacyLights = false;
28551
28552 // tone mapping
28553
28554 this.toneMapping = NoToneMapping;
28555 this.toneMappingExposure = 1.0;
28556
28557 // internal properties
28558
28559 const _this = this;
28560
28561 let _isContextLost = false;
28562
28563 // internal state cache
28564
28568 let _currentMaterialId = - 1;
28569
28570 let _currentCamera = null;
28571
28572 const _currentViewport = new Vector4();
28573 const _currentScissor = new Vector4();
28574 let _currentScissorTest = null;
28575
28576 const _currentClearColor = new Color( 0x000000 );
28578
28579 //
28580
28581 let _width = canvas.width;
28582 let _height = canvas.height;
28583
28584 let _pixelRatio = 1;
28585 let _opaqueSort = null;
28586 let _transparentSort = null;
28587
28588 const _viewport = new Vector4( 0, 0, _width, _height );
28589 const _scissor = new Vector4( 0, 0, _width, _height );
28590 let _scissorTest = false;
28591
28592 // frustum
28593
28594 const _frustum = new Frustum();
28595
28596 // clipping
28597
28598 let _clippingEnabled = false;
28599 let _localClippingEnabled = false;
28600
28601 // transmission
28602
28604
28605 // camera matrices cache
28606
28607 const _projScreenMatrix = new Matrix4();
28608
28609 const _vector2 = new Vector2();
28610 const _vector3 = new Vector3();
28611
28612 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
28613
28614 function getTargetPixelRatio() {
28615
28616 return _currentRenderTarget === null ? _pixelRatio : 1;
28617
28618 }
28619
28620 // initialize
28621
28622 let _gl = context;
28623
28624 function getContext( contextNames, contextAttributes ) {
28625
28626 for ( let i = 0; i < contextNames.length; i ++ ) {
28627
28628 const contextName = contextNames[ i ];
28629 const context = canvas.getContext( contextName, contextAttributes );
28630 if ( context !== null ) return context;
28631
28632 }
28633
28634 return null;
28635
28636 }
28637
28638 try {
28639
28640 const contextAttributes = {
28641 alpha: true,
28642 depth,
28643 stencil,
28644 antialias,
28649 };
28650
28651 // OffscreenCanvas does not have setAttribute, see #22811
28652 if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );
28653
28654 // event listeners must be registered before WebGL context is created, see #12753
28655 canvas.addEventListener( 'webglcontextlost', onContextLost, false );
28656 canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
28657 canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );
28658
28659 if ( _gl === null ) {
28660
28661 const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
28662
28663 if ( _this.isWebGL1Renderer === true ) {
28664
28665 contextNames.shift();
28666
28667 }
28668
28669 _gl = getContext( contextNames, contextAttributes );
28670
28671 if ( _gl === null ) {
28672
28673 if ( getContext( contextNames ) ) {
28674
28675 throw new Error( 'Error creating WebGL context with your selected attributes.' );
28676
28677 } else {
28678
28679 throw new Error( 'Error creating WebGL context.' );
28680
28681 }
28682
28683 }
28684
28685 }
28686
28687 if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153
28688
28689 console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' );
28690
28691 }
28692
28693 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
28694
28695 if ( _gl.getShaderPrecisionFormat === undefined ) {
28696
28697 _gl.getShaderPrecisionFormat = function () {
28698
28699 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
28700
28701 };
28702
28703 }
28704
28705 } catch ( error ) {
28706
28707 console.error( 'THREE.WebGLRenderer: ' + error.message );
28708 throw error;
28709
28710 }
28711
28715
28717
28719
28720 function initGLContext() {
28721
28723
28725
28726 extensions.init( capabilities );
28727
28729
28731
28732 info = new WebGLInfo( _gl );
28733 properties = new WebGLProperties();
28734 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
28735 cubemaps = new WebGLCubeMaps( _this );
28742 clipping = new WebGLClipping( properties );
28744 materials = new WebGLMaterials( _this, properties );
28750
28753
28754 info.programs = programCache.programs;
28755
28756 _this.capabilities = capabilities;
28757 _this.extensions = extensions;
28758 _this.properties = properties;
28759 _this.renderLists = renderLists;
28760 _this.shadowMap = shadowMap;
28761 _this.state = state;
28762 _this.info = info;
28763
28764 }
28765
28766 initGLContext();
28767
28768 // xr
28769
28770 const xr = new WebXRManager( _this, _gl );
28771
28772 this.xr = xr;
28773
28774 // API
28775
28776 this.getContext = function () {
28777
28778 return _gl;
28779
28780 };
28781
28782 this.getContextAttributes = function () {
28783
28784 return _gl.getContextAttributes();
28785
28786 };
28787
28788 this.forceContextLoss = function () {
28789
28790 const extension = extensions.get( 'WEBGL_lose_context' );
28791 if ( extension ) extension.loseContext();
28792
28793 };
28794
28795 this.forceContextRestore = function () {
28796
28797 const extension = extensions.get( 'WEBGL_lose_context' );
28798 if ( extension ) extension.restoreContext();
28799
28800 };
28801
28802 this.getPixelRatio = function () {
28803
28804 return _pixelRatio;
28805
28806 };
28807
28808 this.setPixelRatio = function ( value ) {
28809
28810 if ( value === undefined ) return;
28811
28813
28814 this.setSize( _width, _height, false );
28815
28816 };
28817
28818 this.getSize = function ( target ) {
28819
28820 return target.set( _width, _height );
28821
28822 };
28823
28824 this.setSize = function ( width, height, updateStyle = true ) {
28825
28826 if ( xr.isPresenting ) {
28827
28828 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
28829 return;
28830
28831 }
28832
28833 _width = width;
28834 _height = height;
28835
28836 canvas.width = Math.floor( width * _pixelRatio );
28837 canvas.height = Math.floor( height * _pixelRatio );
28838
28839 if ( updateStyle === true ) {
28840
28841 canvas.style.width = width + 'px';
28842 canvas.style.height = height + 'px';
28843
28844 }
28845
28846 this.setViewport( 0, 0, width, height );
28847
28848 };
28849
28850 this.getDrawingBufferSize = function ( target ) {
28851
28852 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
28853
28854 };
28855
28856 this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
28857
28858 _width = width;
28859 _height = height;
28860
28862
28863 canvas.width = Math.floor( width * pixelRatio );
28864 canvas.height = Math.floor( height * pixelRatio );
28865
28866 this.setViewport( 0, 0, width, height );
28867
28868 };
28869
28870 this.getCurrentViewport = function ( target ) {
28871
28872 return target.copy( _currentViewport );
28873
28874 };
28875
28876 this.getViewport = function ( target ) {
28877
28878 return target.copy( _viewport );
28879
28880 };
28881
28882 this.setViewport = function ( x, y, width, height ) {
28883
28884 if ( x.isVector4 ) {
28885
28886 _viewport.set( x.x, x.y, x.z, x.w );
28887
28888 } else {
28889
28890 _viewport.set( x, y, width, height );
28891
28892 }
28893
28894 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
28895
28896 };
28897
28898 this.getScissor = function ( target ) {
28899
28900 return target.copy( _scissor );
28901
28902 };
28903
28904 this.setScissor = function ( x, y, width, height ) {
28905
28906 if ( x.isVector4 ) {
28907
28908 _scissor.set( x.x, x.y, x.z, x.w );
28909
28910 } else {
28911
28912 _scissor.set( x, y, width, height );
28913
28914 }
28915
28916 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
28917
28918 };
28919
28920 this.getScissorTest = function () {
28921
28922 return _scissorTest;
28923
28924 };
28925
28926 this.setScissorTest = function ( boolean ) {
28927
28928 state.setScissorTest( _scissorTest = boolean );
28929
28930 };
28931
28932 this.setOpaqueSort = function ( method ) {
28933
28934 _opaqueSort = method;
28935
28936 };
28937
28938 this.setTransparentSort = function ( method ) {
28939
28940 _transparentSort = method;
28941
28942 };
28943
28944 // Clearing
28945
28946 this.getClearColor = function ( target ) {
28947
28948 return target.copy( background.getClearColor() );
28949
28950 };
28951
28952 this.setClearColor = function () {
28953
28954 background.setClearColor.apply( background, arguments );
28955
28956 };
28957
28958 this.getClearAlpha = function () {
28959
28960 return background.getClearAlpha();
28961
28962 };
28963
28964 this.setClearAlpha = function () {
28965
28966 background.setClearAlpha.apply( background, arguments );
28967
28968 };
28969
28970 this.clear = function ( color = true, depth = true, stencil = true ) {
28971
28972 let bits = 0;
28973
28974 if ( color ) {
28975
28976 // check if we're trying to clear an integer target
28977 let isIntegerFormat = false;
28978 if ( _currentRenderTarget !== null ) {
28979
28980 const targetFormat = _currentRenderTarget.texture.format;
28984
28985 }
28986
28987 // use the appropriate clear functions to clear the target if it's a signed
28988 // or unsigned integer target
28989 if ( isIntegerFormat ) {
28990
28991 const targetType = _currentRenderTarget.texture.type;
28998
28999 const clearColor = background.getClearColor();
29000 const a = background.getClearAlpha();
29001 const r = clearColor.r;
29002 const g = clearColor.g;
29003 const b = clearColor.b;
29004
29005 if ( isUnsignedType ) {
29006
29007 uintClearColor[ 0 ] = r;
29008 uintClearColor[ 1 ] = g;
29009 uintClearColor[ 2 ] = b;
29010 uintClearColor[ 3 ] = a;
29011 _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );
29012
29013 } else {
29014
29015 intClearColor[ 0 ] = r;
29016 intClearColor[ 1 ] = g;
29017 intClearColor[ 2 ] = b;
29018 intClearColor[ 3 ] = a;
29019 _gl.clearBufferiv( _gl.COLOR, 0, intClearColor );
29020
29021 }
29022
29023 } else {
29024
29025 bits |= _gl.COLOR_BUFFER_BIT;
29026
29027 }
29028
29029 }
29030
29031 if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
29032 if ( stencil ) {
29033
29034 bits |= _gl.STENCIL_BUFFER_BIT;
29035 this.state.buffers.stencil.setMask( 0xffffffff );
29036
29037 }
29038
29039 _gl.clear( bits );
29040
29041 };
29042
29043 this.clearColor = function () {
29044
29045 this.clear( true, false, false );
29046
29047 };
29048
29049 this.clearDepth = function () {
29050
29051 this.clear( false, true, false );
29052
29053 };
29054
29055 this.clearStencil = function () {
29056
29057 this.clear( false, false, true );
29058
29059 };
29060
29061 //
29062
29063 this.dispose = function () {
29064
29065 canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
29066 canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
29067 canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );
29068
29069 renderLists.dispose();
29070 renderStates.dispose();
29071 properties.dispose();
29072 cubemaps.dispose();
29073 cubeuvmaps.dispose();
29074 objects.dispose();
29075 bindingStates.dispose();
29076 uniformsGroups.dispose();
29077 programCache.dispose();
29078
29079 xr.dispose();
29080
29081 xr.removeEventListener( 'sessionstart', onXRSessionStart );
29082 xr.removeEventListener( 'sessionend', onXRSessionEnd );
29083
29085
29086 _transmissionRenderTarget.dispose();
29088
29089 }
29090
29091 animation.stop();
29092
29093 };
29094
29095 // Events
29096
29097 function onContextLost( event ) {
29098
29099 event.preventDefault();
29100
29101 console.log( 'THREE.WebGLRenderer: Context Lost.' );
29102
29103 _isContextLost = true;
29104
29105 }
29106
29107 function onContextRestore( /* event */ ) {
29108
29109 console.log( 'THREE.WebGLRenderer: Context Restored.' );
29110
29111 _isContextLost = false;
29112
29113 const infoAutoReset = info.autoReset;
29114 const shadowMapEnabled = shadowMap.enabled;
29115 const shadowMapAutoUpdate = shadowMap.autoUpdate;
29116 const shadowMapNeedsUpdate = shadowMap.needsUpdate;
29117 const shadowMapType = shadowMap.type;
29118
29119 initGLContext();
29120
29121 info.autoReset = infoAutoReset;
29122 shadowMap.enabled = shadowMapEnabled;
29123 shadowMap.autoUpdate = shadowMapAutoUpdate;
29124 shadowMap.needsUpdate = shadowMapNeedsUpdate;
29125 shadowMap.type = shadowMapType;
29126
29127 }
29128
29129 function onContextCreationError( event ) {
29130
29131 console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );
29132
29133 }
29134
29135 function onMaterialDispose( event ) {
29136
29137 const material = event.target;
29138
29139 material.removeEventListener( 'dispose', onMaterialDispose );
29140
29142
29143 }
29144
29145 // Buffer deallocation
29146
29147 function deallocateMaterial( material ) {
29148
29150
29151 properties.remove( material );
29152
29153 }
29154
29155
29157
29158 const programs = properties.get( material ).programs;
29159
29160 if ( programs !== undefined ) {
29161
29162 programs.forEach( function ( program ) {
29163
29164 programCache.releaseProgram( program );
29165
29166 } );
29167
29168 if ( material.isShaderMaterial ) {
29169
29170 programCache.releaseShaderCache( material );
29171
29172 }
29173
29174 }
29175
29176 }
29177
29178 // Buffer rendering
29179
29180 this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
29181
29182 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
29183
29184 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
29185
29186 const program = setProgram( camera, scene, geometry, material, object );
29187
29188 state.setMaterial( material, frontFaceCW );
29189
29190 //
29191
29192 let index = geometry.index;
29193 let rangeFactor = 1;
29194
29195 if ( material.wireframe === true ) {
29196
29197 index = geometries.getWireframeAttribute( geometry );
29198
29199 if ( index === undefined ) return;
29200
29201 rangeFactor = 2;
29202
29203 }
29204
29205 //
29206
29207 const drawRange = geometry.drawRange;
29208 const position = geometry.attributes.position;
29209
29211 let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;
29212
29213 if ( group !== null ) {
29214
29215 drawStart = Math.max( drawStart, group.start * rangeFactor );
29216 drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );
29217
29218 }
29219
29220 if ( index !== null ) {
29221
29222 drawStart = Math.max( drawStart, 0 );
29223 drawEnd = Math.min( drawEnd, index.count );
29224
29225 } else if ( position !== undefined && position !== null ) {
29226
29227 drawStart = Math.max( drawStart, 0 );
29228 drawEnd = Math.min( drawEnd, position.count );
29229
29230 }
29231
29232 const drawCount = drawEnd - drawStart;
29233
29234 if ( drawCount < 0 || drawCount === Infinity ) return;
29235
29236 //
29237
29238 bindingStates.setup( object, material, program, geometry, index );
29239
29240 let attribute;
29241 let renderer = bufferRenderer;
29242
29243 if ( index !== null ) {
29244
29245 attribute = attributes.get( index );
29246
29247 renderer = indexedBufferRenderer;
29248 renderer.setIndex( attribute );
29249
29250 }
29251
29252 //
29253
29254 if ( object.isMesh ) {
29255
29256 if ( material.wireframe === true ) {
29257
29258 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
29259 renderer.setMode( _gl.LINES );
29260
29261 } else {
29262
29263 renderer.setMode( _gl.TRIANGLES );
29264
29265 }
29266
29267 } else if ( object.isLine ) {
29268
29269 let lineWidth = material.linewidth;
29270
29271 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
29272
29273 state.setLineWidth( lineWidth * getTargetPixelRatio() );
29274
29275 if ( object.isLineSegments ) {
29276
29277 renderer.setMode( _gl.LINES );
29278
29279 } else if ( object.isLineLoop ) {
29280
29281 renderer.setMode( _gl.LINE_LOOP );
29282
29283 } else {
29284
29285 renderer.setMode( _gl.LINE_STRIP );
29286
29287 }
29288
29289 } else if ( object.isPoints ) {
29290
29291 renderer.setMode( _gl.POINTS );
29292
29293 } else if ( object.isSprite ) {
29294
29295 renderer.setMode( _gl.TRIANGLES );
29296
29297 }
29298
29299 if ( object.isBatchedMesh ) {
29300
29301 renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
29302
29303 } else if ( object.isInstancedMesh ) {
29304
29305 renderer.renderInstances( drawStart, drawCount, object.count );
29306
29307 } else if ( geometry.isInstancedBufferGeometry ) {
29308
29309 const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;
29310 const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );
29311
29312 renderer.renderInstances( drawStart, drawCount, instanceCount );
29313
29314 } else {
29315
29316 renderer.render( drawStart, drawCount );
29317
29318 }
29319
29320 };
29321
29322 // Compile
29323
29324 function prepareMaterial( material, scene, object ) {
29325
29326 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29327
29328 material.side = BackSide;
29329 material.needsUpdate = true;
29330 getProgram( material, scene, object );
29331
29332 material.side = FrontSide;
29333 material.needsUpdate = true;
29334 getProgram( material, scene, object );
29335
29336 material.side = DoubleSide;
29337
29338 } else {
29339
29340 getProgram( material, scene, object );
29341
29342 }
29343
29344 }
29345
29346 this.compile = function ( scene, camera, targetScene = null ) {
29347
29348 if ( targetScene === null ) targetScene = scene;
29349
29351 currentRenderState.init();
29352
29354
29355 // gather lights from both the target scene and the new object that will be added to the scene.
29356
29357 targetScene.traverseVisible( function ( object ) {
29358
29359 if ( object.isLight && object.layers.test( camera.layers ) ) {
29360
29361 currentRenderState.pushLight( object );
29362
29363 if ( object.castShadow ) {
29364
29365 currentRenderState.pushShadow( object );
29366
29367 }
29368
29369 }
29370
29371 } );
29372
29373 if ( scene !== targetScene ) {
29374
29375 scene.traverseVisible( function ( object ) {
29376
29377 if ( object.isLight && object.layers.test( camera.layers ) ) {
29378
29379 currentRenderState.pushLight( object );
29380
29381 if ( object.castShadow ) {
29382
29383 currentRenderState.pushShadow( object );
29384
29385 }
29386
29387 }
29388
29389 } );
29390
29391 }
29392
29393 currentRenderState.setupLights( _this._useLegacyLights );
29394
29395 // Only initialize materials in the new scene, not the targetScene.
29396
29397 const materials = new Set();
29398
29399 scene.traverse( function ( object ) {
29400
29401 const material = object.material;
29402
29403 if ( material ) {
29404
29405 if ( Array.isArray( material ) ) {
29406
29407 for ( let i = 0; i < material.length; i ++ ) {
29408
29409 const material2 = material[ i ];
29410
29411 prepareMaterial( material2, targetScene, object );
29412 materials.add( material2 );
29413
29414 }
29415
29416 } else {
29417
29419 materials.add( material );
29420
29421 }
29422
29423 }
29424
29425 } );
29426
29427 renderStateStack.pop();
29428 currentRenderState = null;
29429
29430 return materials;
29431
29432 };
29433
29434 // compileAsync
29435
29436 this.compileAsync = function ( scene, camera, targetScene = null ) {
29437
29438 const materials = this.compile( scene, camera, targetScene );
29439
29440 // Wait for all the materials in the new object to indicate that they're
29441 // ready to be used before resolving the promise.
29442
29443 return new Promise( ( resolve ) => {
29444
29445 function checkMaterialsReady() {
29446
29447 materials.forEach( function ( material ) {
29448
29449 const materialProperties = properties.get( material );
29450 const program = materialProperties.currentProgram;
29451
29452 if ( program.isReady() ) {
29453
29454 // remove any programs that report they're ready to use from the list
29455 materials.delete( material );
29456
29457 }
29458
29459 } );
29460
29461 // once the list of compiling materials is empty, call the callback
29462
29463 if ( materials.size === 0 ) {
29464
29465 resolve( scene );
29466 return;
29467
29468 }
29469
29470 // if some materials are still not ready, wait a bit and check again
29471
29473
29474 }
29475
29476 if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) {
29477
29478 // If we can check the compilation status of the materials without
29479 // blocking then do so right away.
29480
29482
29483 } else {
29484
29485 // Otherwise start by waiting a bit to give the materials we just
29486 // initialized a chance to finish.
29487
29489
29490 }
29491
29492 } );
29493
29494 };
29495
29496 // Animation Loop
29497
29499
29500 function onAnimationFrame( time ) {
29501
29503
29504 }
29505
29506 function onXRSessionStart() {
29507
29508 animation.stop();
29509
29510 }
29511
29512 function onXRSessionEnd() {
29513
29514 animation.start();
29515
29516 }
29517
29518 const animation = new WebGLAnimation();
29519 animation.setAnimationLoop( onAnimationFrame );
29520
29521 if ( typeof self !== 'undefined' ) animation.setContext( self );
29522
29523 this.setAnimationLoop = function ( callback ) {
29524
29525 onAnimationFrameCallback = callback;
29526 xr.setAnimationLoop( callback );
29527
29528 ( callback === null ) ? animation.stop() : animation.start();
29529
29530 };
29531
29532 xr.addEventListener( 'sessionstart', onXRSessionStart );
29533 xr.addEventListener( 'sessionend', onXRSessionEnd );
29534
29535 // Rendering
29536
29537 this.render = function ( scene, camera ) {
29538
29539 if ( camera !== undefined && camera.isCamera !== true ) {
29540
29541 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
29542 return;
29543
29544 }
29545
29546 if ( _isContextLost === true ) return;
29547
29548 // update scene graph
29549
29550 if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
29551
29552 // update camera matrices and frustum
29553
29554 if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
29555
29556 if ( xr.enabled === true && xr.isPresenting === true ) {
29557
29558 if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
29559
29560 camera = xr.getCamera(); // use XR camera for rendering
29561
29562 }
29563
29564 //
29565 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );
29566
29568 currentRenderState.init();
29569
29571
29572 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
29573 _frustum.setFromProjectionMatrix( _projScreenMatrix );
29574
29576 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );
29577
29579 currentRenderList.init();
29580
29582
29583 projectObject( scene, camera, 0, _this.sortObjects );
29584
29585 currentRenderList.finish();
29586
29587 if ( _this.sortObjects === true ) {
29588
29590
29591 }
29592
29593 //
29594
29595 this.info.render.frame ++;
29596
29597 if ( _clippingEnabled === true ) clipping.beginShadows();
29598
29599 const shadowsArray = currentRenderState.state.shadowsArray;
29600
29601 shadowMap.render( shadowsArray, scene, camera );
29602
29603 if ( _clippingEnabled === true ) clipping.endShadows();
29604
29605 //
29606
29607 if ( this.info.autoReset === true ) this.info.reset();
29608
29609
29610 //
29611
29613
29614 // render scene
29615
29616 currentRenderState.setupLights( _this._useLegacyLights );
29617
29618 if ( camera.isArrayCamera ) {
29619
29620 const cameras = camera.cameras;
29621
29622 for ( let i = 0, l = cameras.length; i < l; i ++ ) {
29623
29624 const camera2 = cameras[ i ];
29625
29627
29628 }
29629
29630 } else {
29631
29633
29634 }
29635
29636 //
29637
29638 if ( _currentRenderTarget !== null ) {
29639
29640 // resolve multisample renderbuffers to a single-sample texture if necessary
29641
29642 textures.updateMultisampleRenderTarget( _currentRenderTarget );
29643
29644 // Generate mipmap if we're using any kind of mipmap filtering
29645
29646 textures.updateRenderTargetMipmap( _currentRenderTarget );
29647
29648 }
29649
29650 //
29651
29652 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
29653
29654 // _gl.finish();
29655
29656 bindingStates.resetDefaultState();
29657 _currentMaterialId = - 1;
29658 _currentCamera = null;
29659
29660 renderStateStack.pop();
29661
29662 if ( renderStateStack.length > 0 ) {
29663
29665
29666 } else {
29667
29668 currentRenderState = null;
29669
29670 }
29671
29672 renderListStack.pop();
29673
29674 if ( renderListStack.length > 0 ) {
29675
29677
29678 } else {
29679
29680 currentRenderList = null;
29681
29682 }
29683
29684 };
29685
29686 function projectObject( object, camera, groupOrder, sortObjects ) {
29687
29688 if ( object.visible === false ) return;
29689
29690 const visible = object.layers.test( camera.layers );
29691
29692 if ( visible ) {
29693
29694 if ( object.isGroup ) {
29695
29696 groupOrder = object.renderOrder;
29697
29698 } else if ( object.isLOD ) {
29699
29700 if ( object.autoUpdate === true ) object.update( camera );
29701
29702 } else if ( object.isLight ) {
29703
29704 currentRenderState.pushLight( object );
29705
29706 if ( object.castShadow ) {
29707
29708 currentRenderState.pushShadow( object );
29709
29710 }
29711
29712 } else if ( object.isSprite ) {
29713
29714 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
29715
29716 if ( sortObjects ) {
29717
29718 _vector3.setFromMatrixPosition( object.matrixWorld )
29719 .applyMatrix4( _projScreenMatrix );
29720
29721 }
29722
29723 const geometry = objects.update( object );
29724 const material = object.material;
29725
29726 if ( material.visible ) {
29727
29728 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29729
29730 }
29731
29732 }
29733
29734 } else if ( object.isMesh || object.isLine || object.isPoints ) {
29735
29736 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
29737
29738 const geometry = objects.update( object );
29739 const material = object.material;
29740
29741 if ( sortObjects ) {
29742
29743 if ( object.boundingSphere !== undefined ) {
29744
29745 if ( object.boundingSphere === null ) object.computeBoundingSphere();
29746 _vector3.copy( object.boundingSphere.center );
29747
29748 } else {
29749
29750 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
29751 _vector3.copy( geometry.boundingSphere.center );
29752
29753 }
29754
29755 _vector3
29756 .applyMatrix4( object.matrixWorld )
29757 .applyMatrix4( _projScreenMatrix );
29758
29759 }
29760
29761 if ( Array.isArray( material ) ) {
29762
29763 const groups = geometry.groups;
29764
29765 for ( let i = 0, l = groups.length; i < l; i ++ ) {
29766
29767 const group = groups[ i ];
29768 const groupMaterial = material[ group.materialIndex ];
29769
29770 if ( groupMaterial && groupMaterial.visible ) {
29771
29773
29774 }
29775
29776 }
29777
29778 } else if ( material.visible ) {
29779
29780 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
29781
29782 }
29783
29784 }
29785
29786 }
29787
29788 }
29789
29790 const children = object.children;
29791
29792 for ( let i = 0, l = children.length; i < l; i ++ ) {
29793
29795
29796 }
29797
29798 }
29799
29801
29802 const opaqueObjects = currentRenderList.opaque;
29803 const transmissiveObjects = currentRenderList.transmissive;
29804 const transparentObjects = currentRenderList.transparent;
29805
29806 currentRenderState.setupLightsView( camera );
29807
29808 if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
29809
29811
29812 if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
29813
29814 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
29817
29818 // Ensure depth buffer writing is enabled so it can be cleared on next render
29819
29820 state.buffers.depth.setTest( true );
29821 state.buffers.depth.setMask( true );
29822 state.buffers.color.setMask( true );
29823
29824 state.setPolygonOffset( false );
29825
29826 }
29827
29829
29830 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29831
29832 if ( overrideMaterial !== null ) {
29833
29834 return;
29835
29836 }
29837
29838 const isWebGL2 = capabilities.isWebGL2;
29839
29840 if ( _transmissionRenderTarget === null ) {
29841
29843 generateMipmaps: true,
29844 type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
29846 samples: ( isWebGL2 ) ? 4 : 0
29847 } );
29848
29849 // debug
29850
29851 /*
29852 const geometry = new PlaneGeometry();
29853 const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
29854
29855 const mesh = new Mesh( geometry, material );
29856 scene.add( mesh );
29857 */
29858
29859 }
29860
29861 _this.getDrawingBufferSize( _vector2 );
29862
29863 if ( isWebGL2 ) {
29864
29866
29867 } else {
29868
29870
29871 }
29872
29873 //
29874
29875 const currentRenderTarget = _this.getRenderTarget();
29876 _this.setRenderTarget( _transmissionRenderTarget );
29877
29878 _this.getClearColor( _currentClearColor );
29879 _currentClearAlpha = _this.getClearAlpha();
29880 if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
29881
29882 _this.clear();
29883
29884 // Turn off the features which can affect the frag color for opaque objects pass.
29885 // Otherwise they are applied twice in opaque objects pass and transmission objects pass.
29886 const currentToneMapping = _this.toneMapping;
29887 _this.toneMapping = NoToneMapping;
29888
29890
29891 textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29892 textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29893
29895
29896 for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
29897
29898 const renderItem = transmissiveObjects[ i ];
29899
29900 const object = renderItem.object;
29901 const geometry = renderItem.geometry;
29902 const material = renderItem.material;
29903 const group = renderItem.group;
29904
29905 if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
29906
29907 const currentSide = material.side;
29908
29909 material.side = BackSide;
29910 material.needsUpdate = true;
29911
29913
29914 material.side = currentSide;
29915 material.needsUpdate = true;
29916
29918
29919 }
29920
29921 }
29922
29923 if ( renderTargetNeedsUpdate === true ) {
29924
29925 textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
29926 textures.updateRenderTargetMipmap( _transmissionRenderTarget );
29927
29928 }
29929
29930 _this.setRenderTarget( currentRenderTarget );
29931
29933
29934 _this.toneMapping = currentToneMapping;
29935
29936 }
29937
29938 function renderObjects( renderList, scene, camera ) {
29939
29940 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
29941
29942 for ( let i = 0, l = renderList.length; i < l; i ++ ) {
29943
29944 const renderItem = renderList[ i ];
29945
29946 const object = renderItem.object;
29947 const geometry = renderItem.geometry;
29948 const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
29949 const group = renderItem.group;
29950
29951 if ( object.layers.test( camera.layers ) ) {
29952
29954
29955 }
29956
29957 }
29958
29959 }
29960
29961 function renderObject( object, scene, camera, geometry, material, group ) {
29962
29963 object.onBeforeRender( _this, scene, camera, geometry, material, group );
29964
29965 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
29966 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
29967
29968 material.onBeforeRender( _this, scene, camera, geometry, object, group );
29969
29970 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
29971
29972 material.side = BackSide;
29973 material.needsUpdate = true;
29974 _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29975
29976 material.side = FrontSide;
29977 material.needsUpdate = true;
29978 _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29979
29980 material.side = DoubleSide;
29981
29982 } else {
29983
29984 _this.renderBufferDirect( camera, scene, geometry, material, object, group );
29985
29986 }
29987
29988 object.onAfterRender( _this, scene, camera, geometry, material, group );
29989
29990 }
29991
29992 function getProgram( material, scene, object ) {
29993
29994 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
29995
29996 const materialProperties = properties.get( material );
29997
29998 const lights = currentRenderState.state.lights;
29999 const shadowsArray = currentRenderState.state.shadowsArray;
30000
30001 const lightsStateVersion = lights.state.version;
30002
30003 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
30004 const programCacheKey = programCache.getProgramCacheKey( parameters );
30005
30006 let programs = materialProperties.programs;
30007
30008 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
30009
30010 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
30011 materialProperties.fog = scene.fog;
30012 materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
30013
30014 if ( programs === undefined ) {
30015
30016 // new material
30017
30018 material.addEventListener( 'dispose', onMaterialDispose );
30019
30020 programs = new Map();
30021 materialProperties.programs = programs;
30022
30023 }
30024
30026
30027 if ( program !== undefined ) {
30028
30029 // early out if program and light state is identical
30030
30031 if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
30032
30034
30035 return program;
30036
30037 }
30038
30039 } else {
30040
30041 parameters.uniforms = programCache.getUniforms( material );
30042
30043 material.onBuild( object, parameters, _this );
30044
30045 material.onBeforeCompile( parameters, _this );
30046
30047 program = programCache.acquireProgram( parameters, programCacheKey );
30049
30050 materialProperties.uniforms = parameters.uniforms;
30051
30052 }
30053
30054 const uniforms = materialProperties.uniforms;
30055
30056 if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
30057
30058 uniforms.clippingPlanes = clipping.uniform;
30059
30060 }
30061
30063
30064 // store the light setup it was created for
30065
30067 materialProperties.lightsStateVersion = lightsStateVersion;
30068
30069 if ( materialProperties.needsLights ) {
30070
30071 // wire up the material to this renderer's lighting state
30072
30073 uniforms.ambientLightColor.value = lights.state.ambient;
30074 uniforms.lightProbe.value = lights.state.probe;
30075 uniforms.directionalLights.value = lights.state.directional;
30076 uniforms.directionalLightShadows.value = lights.state.directionalShadow;
30077 uniforms.spotLights.value = lights.state.spot;
30078 uniforms.spotLightShadows.value = lights.state.spotShadow;
30079 uniforms.rectAreaLights.value = lights.state.rectArea;
30080 uniforms.ltc_1.value = lights.state.rectAreaLTC1;
30081 uniforms.ltc_2.value = lights.state.rectAreaLTC2;
30082 uniforms.pointLights.value = lights.state.point;
30083 uniforms.pointLightShadows.value = lights.state.pointShadow;
30084 uniforms.hemisphereLights.value = lights.state.hemi;
30085
30086 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
30087 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
30088 uniforms.spotShadowMap.value = lights.state.spotShadowMap;
30089 uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
30090 uniforms.spotLightMap.value = lights.state.spotLightMap;
30091 uniforms.pointShadowMap.value = lights.state.pointShadowMap;
30092 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
30093 // TODO (abelnation): add area lights shadow info to uniforms
30094
30095 }
30096
30097 materialProperties.currentProgram = program;
30098 materialProperties.uniformsList = null;
30099
30100 return program;
30101
30102 }
30103
30105
30106 if ( materialProperties.uniformsList === null ) {
30107
30108 const progUniforms = materialProperties.currentProgram.getUniforms();
30109 materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );
30110
30111 }
30112
30113 return materialProperties.uniformsList;
30114
30115 }
30116
30118
30119 const materialProperties = properties.get( material );
30120
30121 materialProperties.outputColorSpace = parameters.outputColorSpace;
30122 materialProperties.batching = parameters.batching;
30123 materialProperties.instancing = parameters.instancing;
30124 materialProperties.instancingColor = parameters.instancingColor;
30125 materialProperties.skinning = parameters.skinning;
30126 materialProperties.morphTargets = parameters.morphTargets;
30127 materialProperties.morphNormals = parameters.morphNormals;
30128 materialProperties.morphColors = parameters.morphColors;
30129 materialProperties.morphTargetsCount = parameters.morphTargetsCount;
30130 materialProperties.numClippingPlanes = parameters.numClippingPlanes;
30131 materialProperties.numIntersection = parameters.numClipIntersection;
30132 materialProperties.vertexAlphas = parameters.vertexAlphas;
30133 materialProperties.vertexTangents = parameters.vertexTangents;
30134 materialProperties.toneMapping = parameters.toneMapping;
30135
30136 }
30137
30138 function setProgram( camera, scene, geometry, material, object ) {
30139
30140 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
30141
30142 textures.resetTextureUnits();
30143
30144 const fog = scene.fog;
30145 const environment = material.isMeshStandardMaterial ? scene.environment : null;
30147 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
30148 const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
30149 const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );
30150 const morphTargets = !! geometry.morphAttributes.position;
30151 const morphNormals = !! geometry.morphAttributes.normal;
30152 const morphColors = !! geometry.morphAttributes.color;
30153
30155
30156 if ( material.toneMapped ) {
30157
30158 if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {
30159
30160 toneMapping = _this.toneMapping;
30161
30162 }
30163
30164 }
30165
30166 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
30167 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
30168
30169 const materialProperties = properties.get( material );
30170 const lights = currentRenderState.state.lights;
30171
30172 if ( _clippingEnabled === true ) {
30173
30174 if ( _localClippingEnabled === true || camera !== _currentCamera ) {
30175
30176 const useCache =
30177 camera === _currentCamera &&
30179
30180 // we might want to call this function with some ClippingGroup
30181 // object instead of the material, once it becomes feasible
30182 // (#8465, #8379)
30183 clipping.setState( material, camera, useCache );
30184
30185 }
30186
30187 }
30188
30189 //
30190
30191 let needsProgramChange = false;
30192
30193 if ( material.version === materialProperties.__version ) {
30194
30195 if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
30196
30197 needsProgramChange = true;
30198
30199 } else if ( materialProperties.outputColorSpace !== colorSpace ) {
30200
30201 needsProgramChange = true;
30202
30203 } else if ( object.isBatchedMesh && materialProperties.batching === false ) {
30204
30205 needsProgramChange = true;
30206
30207 } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {
30208
30209 needsProgramChange = true;
30210
30211 } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
30212
30213 needsProgramChange = true;
30214
30215 } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
30216
30217 needsProgramChange = true;
30218
30219 } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {
30220
30221 needsProgramChange = true;
30222
30223 } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {
30224
30225 needsProgramChange = true;
30226
30227 } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {
30228
30229 needsProgramChange = true;
30230
30231 } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {
30232
30233 needsProgramChange = true;
30234
30235 } else if ( materialProperties.envMap !== envMap ) {
30236
30237 needsProgramChange = true;
30238
30239 } else if ( material.fog === true && materialProperties.fog !== fog ) {
30240
30241 needsProgramChange = true;
30242
30243 } else if ( materialProperties.numClippingPlanes !== undefined &&
30244 ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
30245 materialProperties.numIntersection !== clipping.numIntersection ) ) {
30246
30247 needsProgramChange = true;
30248
30249 } else if ( materialProperties.vertexAlphas !== vertexAlphas ) {
30250
30251 needsProgramChange = true;
30252
30253 } else if ( materialProperties.vertexTangents !== vertexTangents ) {
30254
30255 needsProgramChange = true;
30256
30257 } else if ( materialProperties.morphTargets !== morphTargets ) {
30258
30259 needsProgramChange = true;
30260
30261 } else if ( materialProperties.morphNormals !== morphNormals ) {
30262
30263 needsProgramChange = true;
30264
30265 } else if ( materialProperties.morphColors !== morphColors ) {
30266
30267 needsProgramChange = true;
30268
30269 } else if ( materialProperties.toneMapping !== toneMapping ) {
30270
30271 needsProgramChange = true;
30272
30273 } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) {
30274
30275 needsProgramChange = true;
30276
30277 }
30278
30279 } else {
30280
30281 needsProgramChange = true;
30282 materialProperties.__version = material.version;
30283
30284 }
30285
30286 //
30287
30288 let program = materialProperties.currentProgram;
30289
30290 if ( needsProgramChange === true ) {
30291
30292 program = getProgram( material, scene, object );
30293
30294 }
30295
30296 let refreshProgram = false;
30297 let refreshMaterial = false;
30298 let refreshLights = false;
30299
30300 const p_uniforms = program.getUniforms(),
30301 m_uniforms = materialProperties.uniforms;
30302
30303 if ( state.useProgram( program.program ) ) {
30304
30305 refreshProgram = true;
30306 refreshMaterial = true;
30307 refreshLights = true;
30308
30309 }
30310
30311 if ( material.id !== _currentMaterialId ) {
30312
30314
30315 refreshMaterial = true;
30316
30317 }
30318
30319 if ( refreshProgram || _currentCamera !== camera ) {
30320
30321 // common camera uniforms
30322
30323 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
30324 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
30325
30326 const uCamPos = p_uniforms.map.cameraPosition;
30327
30328 if ( uCamPos !== undefined ) {
30329
30330 uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
30331
30332 }
30333
30334 if ( capabilities.logarithmicDepthBuffer ) {
30335
30336 p_uniforms.setValue( _gl, 'logDepthBufFC',
30337 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
30338
30339 }
30340
30341 // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
30342
30343 if ( material.isMeshPhongMaterial ||
30344 material.isMeshToonMaterial ||
30345 material.isMeshLambertMaterial ||
30346 material.isMeshBasicMaterial ||
30347 material.isMeshStandardMaterial ||
30348 material.isShaderMaterial ) {
30349
30350 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
30351
30352 }
30353
30354 if ( _currentCamera !== camera ) {
30355
30357
30358 // lighting uniforms depend on the camera so enforce an update
30359 // now, in case this material supports lights - or later, when
30360 // the next material that does gets activated:
30361
30362 refreshMaterial = true; // set to true on material change
30363 refreshLights = true; // remains set until update done
30364
30365 }
30366
30367 }
30368
30369 // skinning and morph target uniforms must be set even if material didn't change
30370 // auto-setting of texture unit for bone and morph texture must go before other textures
30371 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
30372
30373 if ( object.isSkinnedMesh ) {
30374
30375 p_uniforms.setOptional( _gl, object, 'bindMatrix' );
30376 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
30377
30378 const skeleton = object.skeleton;
30379
30380 if ( skeleton ) {
30381
30382 if ( capabilities.floatVertexTextures ) {
30383
30384 if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();
30385
30386 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
30387
30388 } else {
30389
30390 console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' );
30391
30392 }
30393
30394 }
30395
30396 }
30397
30398 if ( object.isBatchedMesh ) {
30399
30400 p_uniforms.setOptional( _gl, object, 'batchingTexture' );
30401 p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );
30402
30403 }
30404
30405 const morphAttributes = geometry.morphAttributes;
30406
30407 if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
30408
30409 morphtargets.update( object, geometry, program );
30410
30411 }
30412
30413 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
30414
30415 materialProperties.receiveShadow = object.receiveShadow;
30416 p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
30417
30418 }
30419
30420 // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
30421
30422 if ( material.isMeshGouraudMaterial && material.envMap !== null ) {
30423
30424 m_uniforms.envMap.value = envMap;
30425
30426 m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
30427
30428 }
30429
30430 if ( refreshMaterial ) {
30431
30432 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
30433
30434 if ( materialProperties.needsLights ) {
30435
30436 // the current material requires lighting info
30437
30438 // note: all lighting uniforms are always set correctly
30439 // they simply reference the renderer's state for their
30440 // values
30441 //
30442 // use the current material's .needsUpdate flags to set
30443 // the GL state when required
30444
30446
30447 }
30448
30449 // refresh uniforms common to several materials
30450
30451 if ( fog && material.fog === true ) {
30452
30453 materials.refreshFogUniforms( m_uniforms, fog );
30454
30455 }
30456
30457 materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget );
30458
30460
30461 }
30462
30463 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
30464
30466 material.uniformsNeedUpdate = false;
30467
30468 }
30469
30470 if ( material.isSpriteMaterial ) {
30471
30472 p_uniforms.setValue( _gl, 'center', object.center );
30473
30474 }
30475
30476 // common matrices
30477
30478 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
30479 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
30480 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
30481
30482 // UBOs
30483
30484 if ( material.isShaderMaterial || material.isRawShaderMaterial ) {
30485
30486 const groups = material.uniformsGroups;
30487
30488 for ( let i = 0, l = groups.length; i < l; i ++ ) {
30489
30490 if ( capabilities.isWebGL2 ) {
30491
30492 const group = groups[ i ];
30493
30494 uniformsGroups.update( group, program );
30495 uniformsGroups.bind( group, program );
30496
30497 } else {
30498
30499 console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' );
30500
30501 }
30502
30503 }
30504
30505 }
30506
30507 return program;
30508
30509 }
30510
30511 // If uniforms are marked as clean, they don't need to be loaded to the GPU.
30512
30514
30515 uniforms.ambientLightColor.needsUpdate = value;
30516 uniforms.lightProbe.needsUpdate = value;
30517
30518 uniforms.directionalLights.needsUpdate = value;
30519 uniforms.directionalLightShadows.needsUpdate = value;
30520 uniforms.pointLights.needsUpdate = value;
30521 uniforms.pointLightShadows.needsUpdate = value;
30522 uniforms.spotLights.needsUpdate = value;
30523 uniforms.spotLightShadows.needsUpdate = value;
30524 uniforms.rectAreaLights.needsUpdate = value;
30525 uniforms.hemisphereLights.needsUpdate = value;
30526
30527 }
30528
30529 function materialNeedsLights( material ) {
30530
30531 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
30532 material.isMeshStandardMaterial || material.isShadowMaterial ||
30533 ( material.isShaderMaterial && material.lights === true );
30534
30535 }
30536
30537 this.getActiveCubeFace = function () {
30538
30540
30541 };
30542
30543 this.getActiveMipmapLevel = function () {
30544
30546
30547 };
30548
30549 this.getRenderTarget = function () {
30550
30551 return _currentRenderTarget;
30552
30553 };
30554
30556
30557 properties.get( renderTarget.texture ).__webglTexture = colorTexture;
30558 properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;
30559
30560 const renderTargetProperties = properties.get( renderTarget );
30561 renderTargetProperties.__hasExternalTextures = true;
30562
30563 if ( renderTargetProperties.__hasExternalTextures ) {
30564
30565 renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
30566
30567 if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
30568
30569 // The multisample_render_to_texture extension doesn't work properly if there
30570 // are midframe flushes and an external depth buffer. Disable use of the extension.
30571 if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {
30572
30573 console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
30574 renderTargetProperties.__useRenderToTexture = false;
30575
30576 }
30577
30578 }
30579
30580 }
30581
30582 };
30583
30585
30586 const renderTargetProperties = properties.get( renderTarget );
30587 renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
30588 renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;
30589
30590 };
30591
30592 this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
30593
30594 _currentRenderTarget = renderTarget;
30597
30599 let framebuffer = null;
30600 let isCube = false;
30601 let isRenderTarget3D = false;
30602
30603 if ( renderTarget ) {
30604
30605 const renderTargetProperties = properties.get( renderTarget );
30606
30607 if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {
30608
30609 // We need to make sure to rebind the framebuffer.
30610 state.bindFramebuffer( _gl.FRAMEBUFFER, null );
30611 useDefaultFramebuffer = false;
30612
30613 } else if ( renderTargetProperties.__webglFramebuffer === undefined ) {
30614
30615 textures.setupRenderTarget( renderTarget );
30616
30617 } else if ( renderTargetProperties.__hasExternalTextures ) {
30618
30619 // Color and depth texture must be rebound in order for the swapchain to update.
30620 textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );
30621
30622 }
30623
30624 const texture = renderTarget.texture;
30625
30626 if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30627
30628 isRenderTarget3D = true;
30629
30630 }
30631
30632 const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
30633
30634 if ( renderTarget.isWebGLCubeRenderTarget ) {
30635
30636 if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {
30637
30639
30640 } else {
30641
30643
30644 }
30645
30646 isCube = true;
30647
30648 } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {
30649
30650 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
30651
30652 } else {
30653
30654 if ( Array.isArray( __webglFramebuffer ) ) {
30655
30657
30658 } else {
30659
30661
30662 }
30663
30664 }
30665
30666 _currentViewport.copy( renderTarget.viewport );
30667 _currentScissor.copy( renderTarget.scissor );
30668 _currentScissorTest = renderTarget.scissorTest;
30669
30670 } else {
30671
30672 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
30673 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
30675
30676 }
30677
30678 const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30679
30680 if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) {
30681
30682 state.drawBuffers( renderTarget, framebuffer );
30683
30684 }
30685
30686 state.viewport( _currentViewport );
30687 state.scissor( _currentScissor );
30688 state.setScissorTest( _currentScissorTest );
30689
30690 if ( isCube ) {
30691
30692 const textureProperties = properties.get( renderTarget.texture );
30693 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
30694
30695 } else if ( isRenderTarget3D ) {
30696
30697 const textureProperties = properties.get( renderTarget.texture );
30698 const layer = activeCubeFace || 0;
30699 _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );
30700
30701 }
30702
30703 _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings
30704
30705 };
30706
30708
30709 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
30710
30711 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
30712 return;
30713
30714 }
30715
30716 let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
30717
30718 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
30719
30721
30722 }
30723
30724 if ( framebuffer ) {
30725
30726 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30727
30728 try {
30729
30730 const texture = renderTarget.texture;
30731 const textureFormat = texture.format;
30732 const textureType = texture.type;
30733
30734 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
30735
30736 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
30737 return;
30738
30739 }
30740
30741 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
30742
30743 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
30744 ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
30746
30747 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
30748 return;
30749
30750 }
30751
30752 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
30753
30754 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
30755
30756 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
30757
30758 }
30759
30760 } finally {
30761
30762 // restore framebuffer of current render target if necessary
30763
30764 const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
30765 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
30766
30767 }
30768
30769 }
30770
30771 };
30772
30773 this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
30774
30775 const levelScale = Math.pow( 2, - level );
30776 const width = Math.floor( texture.image.width * levelScale );
30777 const height = Math.floor( texture.image.height * levelScale );
30778
30779 textures.setTexture2D( texture, 0 );
30780
30781 _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height );
30782
30783 state.unbindTexture();
30784
30785 };
30786
30787 this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
30788
30789 const width = srcTexture.image.width;
30790 const height = srcTexture.image.height;
30791 const glFormat = utils.convert( dstTexture.format );
30792 const glType = utils.convert( dstTexture.type );
30793
30794 textures.setTexture2D( dstTexture, 0 );
30795
30796 // As another texture upload may have changed pixelStorei
30797 // parameters, make sure they are correct for the dstTexture
30798 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30799 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30800 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30801
30802 if ( srcTexture.isDataTexture ) {
30803
30804 _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
30805
30806 } else {
30807
30808 if ( srcTexture.isCompressedTexture ) {
30809
30810 _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
30811
30812 } else {
30813
30814 _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
30815
30816 }
30817
30818 }
30819
30820 // Generate mipmaps only when copying level 0
30821 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );
30822
30823 state.unbindTexture();
30824
30825 };
30826
30827 this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
30828
30829 if ( _this.isWebGL1Renderer ) {
30830
30831 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' );
30832 return;
30833
30834 }
30835
30836 const width = sourceBox.max.x - sourceBox.min.x + 1;
30837 const height = sourceBox.max.y - sourceBox.min.y + 1;
30838 const depth = sourceBox.max.z - sourceBox.min.z + 1;
30839 const glFormat = utils.convert( dstTexture.format );
30840 const glType = utils.convert( dstTexture.type );
30841 let glTarget;
30842
30843 if ( dstTexture.isData3DTexture ) {
30844
30845 textures.setTexture3D( dstTexture, 0 );
30846 glTarget = _gl.TEXTURE_3D;
30847
30848 } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {
30849
30850 textures.setTexture2DArray( dstTexture, 0 );
30851 glTarget = _gl.TEXTURE_2D_ARRAY;
30852
30853 } else {
30854
30855 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );
30856 return;
30857
30858 }
30859
30860 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
30861 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
30862 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
30863
30864 const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
30865 const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
30866 const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
30867 const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
30868 const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );
30869
30870 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;
30871
30872 _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
30873 _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
30874 _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x );
30875 _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );
30876 _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z );
30877
30878 if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {
30879
30880 _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
30881
30882 } else {
30883
30884 if ( srcTexture.isCompressedArrayTexture ) {
30885
30886 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' );
30887 _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
30888
30889 } else {
30890
30891 _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
30892
30893 }
30894
30895 }
30896
30897 _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen );
30898 _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight );
30899 _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels );
30900 _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows );
30901 _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages );
30902
30903 // Generate mipmaps only when copying level 0
30904 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
30905
30906 state.unbindTexture();
30907
30908 };
30909
30910 this.initTexture = function ( texture ) {
30911
30912 if ( texture.isCubeTexture ) {
30913
30914 textures.setTextureCube( texture, 0 );
30915
30916 } else if ( texture.isData3DTexture ) {
30917
30918 textures.setTexture3D( texture, 0 );
30919
30920 } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
30921
30922 textures.setTexture2DArray( texture, 0 );
30923
30924 } else {
30925
30926 textures.setTexture2D( texture, 0 );
30927
30928 }
30929
30930 state.unbindTexture();
30931
30932 };
30933
30934 this.resetState = function () {
30935
30936 _currentActiveCubeFace = 0;
30938 _currentRenderTarget = null;
30939
30940 state.reset();
30941 bindingStates.reset();
30942
30943 };
30944
30945 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
30946
30947 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
30948
30949 }
30950
30951 }
30952
30953 get coordinateSystem() {
30954
30955 return WebGLCoordinateSystem;
30956
30957 }
30958
30959 get outputColorSpace() {
30960
30961 return this._outputColorSpace;
30962
30963 }
30964
30966
30968
30969 const gl = this.getContext();
30970 gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';
30971 gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';
30972
30973 }
30974
30975 get outputEncoding() { // @deprecated, r152
30976
30977 console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30979
30980 }
30981
30982 set outputEncoding( encoding ) { // @deprecated, r152
30983
30984 console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
30986
30987 }
30988
30989 get useLegacyLights() { // @deprecated, r155
30990
30991 console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
30992 return this._useLegacyLights;
30993
30994 }
30995
30996 set useLegacyLights( value ) { // @deprecated, r155
30997
30998 console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
30999 this._useLegacyLights = value;
31000
31001 }
31002
31003 }
31004
31005 class WebGL1Renderer extends WebGLRenderer {}
31006
31007 WebGL1Renderer.prototype.isWebGL1Renderer = true;
31008
31009 class FogExp2 {
31010
31011 constructor( color, density = 0.00025 ) {
31012
31013 this.isFogExp2 = true;
31014
31015 this.name = '';
31016
31017 this.color = new Color( color );
31018 this.density = density;
31019
31020 }
31021
31022 clone() {
31023
31024 return new FogExp2( this.color, this.density );
31025
31026 }
31027
31028 toJSON( /* meta */ ) {
31029
31030 return {
31031 type: 'FogExp2',
31032 name: this.name,
31033 color: this.color.getHex(),
31034 density: this.density
31035 };
31036
31037 }
31038
31039 }
31040
31041 class Fog {
31042
31043 constructor( color, near = 1, far = 1000 ) {
31044
31045 this.isFog = true;
31046
31047 this.name = '';
31048
31049 this.color = new Color( color );
31050
31051 this.near = near;
31052 this.far = far;
31053
31054 }
31055
31056 clone() {
31057
31058 return new Fog( this.color, this.near, this.far );
31059
31060 }
31061
31062 toJSON( /* meta */ ) {
31063
31064 return {
31065 type: 'Fog',
31066 name: this.name,
31067 color: this.color.getHex(),
31068 near: this.near,
31069 far: this.far
31070 };
31071
31072 }
31073
31074 }
31075
31076 class Scene extends Object3D {
31077
31078 constructor() {
31079
31080 super();
31081
31082 this.isScene = true;
31083
31084 this.type = 'Scene';
31085
31086 this.background = null;
31087 this.environment = null;
31088 this.fog = null;
31089
31090 this.backgroundBlurriness = 0;
31091 this.backgroundIntensity = 1;
31092
31093 this.overrideMaterial = null;
31094
31095 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
31096
31097 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
31098
31099 }
31100
31101 }
31102
31103 copy( source, recursive ) {
31104
31105 super.copy( source, recursive );
31106
31107 if ( source.background !== null ) this.background = source.background.clone();
31108 if ( source.environment !== null ) this.environment = source.environment.clone();
31109 if ( source.fog !== null ) this.fog = source.fog.clone();
31110
31111 this.backgroundBlurriness = source.backgroundBlurriness;
31112 this.backgroundIntensity = source.backgroundIntensity;
31113
31114 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
31115
31116 this.matrixAutoUpdate = source.matrixAutoUpdate;
31117
31118 return this;
31119
31120 }
31121
31122 toJSON( meta ) {
31123
31124 const data = super.toJSON( meta );
31125
31126 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
31127 if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness;
31128 if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity;
31129
31130 return data;
31131
31132 }
31133
31134 }
31135
31136 class InterleavedBuffer {
31137
31139
31140 this.isInterleavedBuffer = true;
31141
31142 this.array = array;
31143 this.stride = stride;
31144 this.count = array !== undefined ? array.length / stride : 0;
31145
31146 this.usage = StaticDrawUsage;
31147 this._updateRange = { offset: 0, count: - 1 };
31148 this.updateRanges = [];
31149
31150 this.version = 0;
31151
31152 this.uuid = generateUUID();
31153
31154 }
31155
31156 onUploadCallback() {}
31157
31158 set needsUpdate( value ) {
31159
31160 if ( value === true ) this.version ++;
31161
31162 }
31163
31164 get updateRange() {
31165
31166 console.warn( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
31167 return this._updateRange;
31168
31169 }
31170
31171 setUsage( value ) {
31172
31173 this.usage = value;
31174
31175 return this;
31176
31177 }
31178
31179 addUpdateRange( start, count ) {
31180
31181 this.updateRanges.push( { start, count } );
31182
31183 }
31184
31186
31187 this.updateRanges.length = 0;
31188
31189 }
31190
31191 copy( source ) {
31192
31193 this.array = new source.array.constructor( source.array );
31194 this.count = source.count;
31195 this.stride = source.stride;
31196 this.usage = source.usage;
31197
31198 return this;
31199
31200 }
31201
31202 copyAt( index1, attribute, index2 ) {
31203
31204 index1 *= this.stride;
31205 index2 *= attribute.stride;
31206
31207 for ( let i = 0, l = this.stride; i < l; i ++ ) {
31208
31209 this.array[ index1 + i ] = attribute.array[ index2 + i ];
31210
31211 }
31212
31213 return this;
31214
31215 }
31216
31217 set( value, offset = 0 ) {
31218
31219 this.array.set( value, offset );
31220
31221 return this;
31222
31223 }
31224
31225 clone( data ) {
31226
31227 if ( data.arrayBuffers === undefined ) {
31228
31229 data.arrayBuffers = {};
31230
31231 }
31232
31233 if ( this.array.buffer._uuid === undefined ) {
31234
31235 this.array.buffer._uuid = generateUUID();
31236
31237 }
31238
31239 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31240
31241 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;
31242
31243 }
31244
31245 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );
31246
31247 const ib = new this.constructor( array, this.stride );
31248 ib.setUsage( this.usage );
31249
31250 return ib;
31251
31252 }
31253
31254 onUpload( callback ) {
31255
31257
31258 return this;
31259
31260 }
31261
31262 toJSON( data ) {
31263
31264 if ( data.arrayBuffers === undefined ) {
31265
31266 data.arrayBuffers = {};
31267
31268 }
31269
31270 // generate UUID for array buffer if necessary
31271
31272 if ( this.array.buffer._uuid === undefined ) {
31273
31274 this.array.buffer._uuid = generateUUID();
31275
31276 }
31277
31278 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {
31279
31280 data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );
31281
31282 }
31283
31284 //
31285
31286 return {
31287 uuid: this.uuid,
31288 buffer: this.array.buffer._uuid,
31289 type: this.array.constructor.name,
31290 stride: this.stride
31291 };
31292
31293 }
31294
31295 }
31296
31297 const _vector$6 = /*@__PURE__*/ new Vector3();
31298
31300
31301 constructor( interleavedBuffer, itemSize, offset, normalized = false ) {
31302
31303 this.isInterleavedBufferAttribute = true;
31304
31305 this.name = '';
31306
31307 this.data = interleavedBuffer;
31308 this.itemSize = itemSize;
31309 this.offset = offset;
31310
31311 this.normalized = normalized;
31312
31313 }
31314
31315 get count() {
31316
31317 return this.data.count;
31318
31319 }
31320
31321 get array() {
31322
31323 return this.data.array;
31324
31325 }
31326
31327 set needsUpdate( value ) {
31328
31329 this.data.needsUpdate = value;
31330
31331 }
31332
31333 applyMatrix4( m ) {
31334
31335 for ( let i = 0, l = this.data.count; i < l; i ++ ) {
31336
31337 _vector$6.fromBufferAttribute( this, i );
31338
31339 _vector$6.applyMatrix4( m );
31340
31341 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31342
31343 }
31344
31345 return this;
31346
31347 }
31348
31349 applyNormalMatrix( m ) {
31350
31351 for ( let i = 0, l = this.count; i < l; i ++ ) {
31352
31353 _vector$6.fromBufferAttribute( this, i );
31354
31355 _vector$6.applyNormalMatrix( m );
31356
31357 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31358
31359 }
31360
31361 return this;
31362
31363 }
31364
31366
31367 for ( let i = 0, l = this.count; i < l; i ++ ) {
31368
31369 _vector$6.fromBufferAttribute( this, i );
31370
31371 _vector$6.transformDirection( m );
31372
31373 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );
31374
31375 }
31376
31377 return this;
31378
31379 }
31380
31381 setX( index, x ) {
31382
31383 if ( this.normalized ) x = normalize( x, this.array );
31384
31385 this.data.array[ index * this.data.stride + this.offset ] = x;
31386
31387 return this;
31388
31389 }
31390
31391 setY( index, y ) {
31392
31393 if ( this.normalized ) y = normalize( y, this.array );
31394
31395 this.data.array[ index * this.data.stride + this.offset + 1 ] = y;
31396
31397 return this;
31398
31399 }
31400
31401 setZ( index, z ) {
31402
31403 if ( this.normalized ) z = normalize( z, this.array );
31404
31405 this.data.array[ index * this.data.stride + this.offset + 2 ] = z;
31406
31407 return this;
31408
31409 }
31410
31411 setW( index, w ) {
31412
31413 if ( this.normalized ) w = normalize( w, this.array );
31414
31415 this.data.array[ index * this.data.stride + this.offset + 3 ] = w;
31416
31417 return this;
31418
31419 }
31420
31421 getX( index ) {
31422
31423 let x = this.data.array[ index * this.data.stride + this.offset ];
31424
31425 if ( this.normalized ) x = denormalize( x, this.array );
31426
31427 return x;
31428
31429 }
31430
31431 getY( index ) {
31432
31433 let y = this.data.array[ index * this.data.stride + this.offset + 1 ];
31434
31435 if ( this.normalized ) y = denormalize( y, this.array );
31436
31437 return y;
31438
31439 }
31440
31441 getZ( index ) {
31442
31443 let z = this.data.array[ index * this.data.stride + this.offset + 2 ];
31444
31445 if ( this.normalized ) z = denormalize( z, this.array );
31446
31447 return z;
31448
31449 }
31450
31451 getW( index ) {
31452
31453 let w = this.data.array[ index * this.data.stride + this.offset + 3 ];
31454
31455 if ( this.normalized ) w = denormalize( w, this.array );
31456
31457 return w;
31458
31459 }
31460
31461 setXY( index, x, y ) {
31462
31463 index = index * this.data.stride + this.offset;
31464
31465 if ( this.normalized ) {
31466
31467 x = normalize( x, this.array );
31468 y = normalize( y, this.array );
31469
31470 }
31471
31472 this.data.array[ index + 0 ] = x;
31473 this.data.array[ index + 1 ] = y;
31474
31475 return this;
31476
31477 }
31478
31479 setXYZ( index, x, y, z ) {
31480
31481 index = index * this.data.stride + this.offset;
31482
31483 if ( this.normalized ) {
31484
31485 x = normalize( x, this.array );
31486 y = normalize( y, this.array );
31487 z = normalize( z, this.array );
31488
31489 }
31490
31491 this.data.array[ index + 0 ] = x;
31492 this.data.array[ index + 1 ] = y;
31493 this.data.array[ index + 2 ] = z;
31494
31495 return this;
31496
31497 }
31498
31499 setXYZW( index, x, y, z, w ) {
31500
31501 index = index * this.data.stride + this.offset;
31502
31503 if ( this.normalized ) {
31504
31505 x = normalize( x, this.array );
31506 y = normalize( y, this.array );
31507 z = normalize( z, this.array );
31508 w = normalize( w, this.array );
31509
31510 }
31511
31512 this.data.array[ index + 0 ] = x;
31513 this.data.array[ index + 1 ] = y;
31514 this.data.array[ index + 2 ] = z;
31515 this.data.array[ index + 3 ] = w;
31516
31517 return this;
31518
31519 }
31520
31521 clone( data ) {
31522
31523 if ( data === undefined ) {
31524
31525 console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );
31526
31527 const array = [];
31528
31529 for ( let i = 0; i < this.count; i ++ ) {
31530
31531 const index = i * this.data.stride + this.offset;
31532
31533 for ( let j = 0; j < this.itemSize; j ++ ) {
31534
31535 array.push( this.data.array[ index + j ] );
31536
31537 }
31538
31539 }
31540
31541 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );
31542
31543 } else {
31544
31545 if ( data.interleavedBuffers === undefined ) {
31546
31547 data.interleavedBuffers = {};
31548
31549 }
31550
31551 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31552
31553 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );
31554
31555 }
31556
31557 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );
31558
31559 }
31560
31561 }
31562
31563 toJSON( data ) {
31564
31565 if ( data === undefined ) {
31566
31567 console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );
31568
31569 const array = [];
31570
31571 for ( let i = 0; i < this.count; i ++ ) {
31572
31573 const index = i * this.data.stride + this.offset;
31574
31575 for ( let j = 0; j < this.itemSize; j ++ ) {
31576
31577 array.push( this.data.array[ index + j ] );
31578
31579 }
31580
31581 }
31582
31583 // de-interleave data and save it as an ordinary buffer attribute for now
31584
31585 return {
31586 itemSize: this.itemSize,
31587 type: this.array.constructor.name,
31588 array: array,
31590 };
31591
31592 } else {
31593
31594 // save as true interleaved attribute
31595
31596 if ( data.interleavedBuffers === undefined ) {
31597
31598 data.interleavedBuffers = {};
31599
31600 }
31601
31602 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {
31603
31604 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );
31605
31606 }
31607
31608 return {
31610 itemSize: this.itemSize,
31611 data: this.data.uuid,
31612 offset: this.offset,
31614 };
31615
31616 }
31617
31618 }
31619
31620 }
31621
31622 class SpriteMaterial extends Material {
31623
31624 constructor( parameters ) {
31625
31626 super();
31627
31628 this.isSpriteMaterial = true;
31629
31630 this.type = 'SpriteMaterial';
31631
31632 this.color = new Color( 0xffffff );
31633
31634 this.map = null;
31635
31636 this.alphaMap = null;
31637
31638 this.rotation = 0;
31639
31640 this.sizeAttenuation = true;
31641
31642 this.transparent = true;
31643
31644 this.fog = true;
31645
31646 this.setValues( parameters );
31647
31648 }
31649
31650 copy( source ) {
31651
31652 super.copy( source );
31653
31654 this.color.copy( source.color );
31655
31656 this.map = source.map;
31657
31658 this.alphaMap = source.alphaMap;
31659
31660 this.rotation = source.rotation;
31661
31662 this.sizeAttenuation = source.sizeAttenuation;
31663
31664 this.fog = source.fog;
31665
31666 return this;
31667
31668 }
31669
31670 }
31671
31672 let _geometry;
31673
31674 const _intersectPoint = /*@__PURE__*/ new Vector3();
31675 const _worldScale = /*@__PURE__*/ new Vector3();
31676 const _mvPosition = /*@__PURE__*/ new Vector3();
31677
31678 const _alignedPosition = /*@__PURE__*/ new Vector2();
31679 const _rotatedPosition = /*@__PURE__*/ new Vector2();
31680 const _viewWorldMatrix = /*@__PURE__*/ new Matrix4();
31681
31682 const _vA = /*@__PURE__*/ new Vector3();
31683 const _vB = /*@__PURE__*/ new Vector3();
31684 const _vC = /*@__PURE__*/ new Vector3();
31685
31686 const _uvA = /*@__PURE__*/ new Vector2();
31687 const _uvB = /*@__PURE__*/ new Vector2();
31688 const _uvC = /*@__PURE__*/ new Vector2();
31689
31690 class Sprite extends Object3D {
31691
31692 constructor( material = new SpriteMaterial() ) {
31693
31694 super();
31695
31696 this.isSprite = true;
31697
31698 this.type = 'Sprite';
31699
31700 if ( _geometry === undefined ) {
31701
31702 _geometry = new BufferGeometry();
31703
31704 const float32Array = new Float32Array( [
31705 - 0.5, - 0.5, 0, 0, 0,
31706 0.5, - 0.5, 0, 1, 0,
31707 0.5, 0.5, 0, 1, 1,
31708 - 0.5, 0.5, 0, 0, 1
31709 ] );
31710
31712
31713 _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] );
31714 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
31715 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
31716
31717 }
31718
31719 this.geometry = _geometry;
31720 this.material = material;
31721
31722 this.center = new Vector2( 0.5, 0.5 );
31723
31724 }
31725
31727
31728 if ( raycaster.camera === null ) {
31729
31730 console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' );
31731
31732 }
31733
31734 _worldScale.setFromMatrixScale( this.matrixWorld );
31735
31736 _viewWorldMatrix.copy( raycaster.camera.matrixWorld );
31737 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );
31738
31739 _mvPosition.setFromMatrixPosition( this.modelViewMatrix );
31740
31741 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
31742
31743 _worldScale.multiplyScalar( - _mvPosition.z );
31744
31745 }
31746
31747 const rotation = this.material.rotation;
31748 let sin, cos;
31749
31750 if ( rotation !== 0 ) {
31751
31752 cos = Math.cos( rotation );
31753 sin = Math.sin( rotation );
31754
31755 }
31756
31757 const center = this.center;
31758
31759 transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31760 transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31761 transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31762
31763 _uvA.set( 0, 0 );
31764 _uvB.set( 1, 0 );
31765 _uvC.set( 1, 1 );
31766
31767 // check first triangle
31768 let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );
31769
31770 if ( intersect === null ) {
31771
31772 // check second triangle
31773 transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );
31774 _uvB.set( 0, 1 );
31775
31776 intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );
31777 if ( intersect === null ) {
31778
31779 return;
31780
31781 }
31782
31783 }
31784
31785 const distance = raycaster.ray.origin.distanceTo( _intersectPoint );
31786
31788
31789 intersects.push( {
31790
31792 point: _intersectPoint.clone(),
31794 face: null,
31795 object: this
31796
31797 } );
31798
31799 }
31800
31801 copy( source, recursive ) {
31802
31803 super.copy( source, recursive );
31804
31805 if ( source.center !== undefined ) this.center.copy( source.center );
31806
31807 this.material = source.material;
31808
31809 return this;
31810
31811 }
31812
31813 }
31814
31816
31817 // compute position in camera space
31818 _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );
31819
31820 // to check if rotation is not zero
31821 if ( sin !== undefined ) {
31822
31825
31826 } else {
31827
31829
31830 }
31831
31832
31833 vertexPosition.copy( mvPosition );
31836
31837 // transform to world space
31838 vertexPosition.applyMatrix4( _viewWorldMatrix );
31839
31840 }
31841
31842 const _v1$2 = /*@__PURE__*/ new Vector3();
31843 const _v2$1 = /*@__PURE__*/ new Vector3();
31844
31845 class LOD extends Object3D {
31846
31847 constructor() {
31848
31849 super();
31850
31851 this._currentLevel = 0;
31852
31853 this.type = 'LOD';
31854
31855 Object.defineProperties( this, {
31856 levels: {
31857 enumerable: true,
31858 value: []
31859 },
31860 isLOD: {
31861 value: true,
31862 }
31863 } );
31864
31865 this.autoUpdate = true;
31866
31867 }
31868
31869 copy( source ) {
31870
31871 super.copy( source, false );
31872
31873 const levels = source.levels;
31874
31875 for ( let i = 0, l = levels.length; i < l; i ++ ) {
31876
31877 const level = levels[ i ];
31878
31879 this.addLevel( level.object.clone(), level.distance, level.hysteresis );
31880
31881 }
31882
31883 this.autoUpdate = source.autoUpdate;
31884
31885 return this;
31886
31887 }
31888
31889 addLevel( object, distance = 0, hysteresis = 0 ) {
31890
31891 distance = Math.abs( distance );
31892
31893 const levels = this.levels;
31894
31895 let l;
31896
31897 for ( l = 0; l < levels.length; l ++ ) {
31898
31899 if ( distance < levels[ l ].distance ) {
31900
31901 break;
31902
31903 }
31904
31905 }
31906
31907 levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );
31908
31909 this.add( object );
31910
31911 return this;
31912
31913 }
31914
31915 getCurrentLevel() {
31916
31917 return this._currentLevel;
31918
31919 }
31920
31921
31922
31924
31925 const levels = this.levels;
31926
31927 if ( levels.length > 0 ) {
31928
31929 let i, l;
31930
31931 for ( i = 1, l = levels.length; i < l; i ++ ) {
31932
31933 let levelDistance = levels[ i ].distance;
31934
31935 if ( levels[ i ].object.visible ) {
31936
31937 levelDistance -= levelDistance * levels[ i ].hysteresis;
31938
31939 }
31940
31941 if ( distance < levelDistance ) {
31942
31943 break;
31944
31945 }
31946
31947 }
31948
31949 return levels[ i - 1 ].object;
31950
31951 }
31952
31953 return null;
31954
31955 }
31956
31958
31959 const levels = this.levels;
31960
31961 if ( levels.length > 0 ) {
31962
31963 _v1$2.setFromMatrixPosition( this.matrixWorld );
31964
31965 const distance = raycaster.ray.origin.distanceTo( _v1$2 );
31966
31968
31969 }
31970
31971 }
31972
31973 update( camera ) {
31974
31975 const levels = this.levels;
31976
31977 if ( levels.length > 1 ) {
31978
31979 _v1$2.setFromMatrixPosition( camera.matrixWorld );
31980 _v2$1.setFromMatrixPosition( this.matrixWorld );
31981
31982 const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom;
31983
31984 levels[ 0 ].object.visible = true;
31985
31986 let i, l;
31987
31988 for ( i = 1, l = levels.length; i < l; i ++ ) {
31989
31990 let levelDistance = levels[ i ].distance;
31991
31992 if ( levels[ i ].object.visible ) {
31993
31994 levelDistance -= levelDistance * levels[ i ].hysteresis;
31995
31996 }
31997
31998 if ( distance >= levelDistance ) {
31999
32000 levels[ i - 1 ].object.visible = false;
32001 levels[ i ].object.visible = true;
32002
32003 } else {
32004
32005 break;
32006
32007 }
32008
32009 }
32010
32011 this._currentLevel = i - 1;
32012
32013 for ( ; i < l; i ++ ) {
32014
32015 levels[ i ].object.visible = false;
32016
32017 }
32018
32019 }
32020
32021 }
32022
32023 toJSON( meta ) {
32024
32025 const data = super.toJSON( meta );
32026
32027 if ( this.autoUpdate === false ) data.object.autoUpdate = false;
32028
32029 data.object.levels = [];
32030
32031 const levels = this.levels;
32032
32033 for ( let i = 0, l = levels.length; i < l; i ++ ) {
32034
32035 const level = levels[ i ];
32036
32037 data.object.levels.push( {
32038 object: level.object.uuid,
32039 distance: level.distance,
32040 hysteresis: level.hysteresis
32041 } );
32042
32043 }
32044
32045 return data;
32046
32047 }
32048
32049 }
32050
32051 const _basePosition = /*@__PURE__*/ new Vector3();
32052
32053 const _skinIndex = /*@__PURE__*/ new Vector4();
32054 const _skinWeight = /*@__PURE__*/ new Vector4();
32055
32056 const _vector3 = /*@__PURE__*/ new Vector3();
32057 const _matrix4 = /*@__PURE__*/ new Matrix4();
32058 const _vertex = /*@__PURE__*/ new Vector3();
32059
32060 const _sphere$4 = /*@__PURE__*/ new Sphere();
32061 const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();
32062 const _ray$2 = /*@__PURE__*/ new Ray();
32063
32064 class SkinnedMesh extends Mesh {
32065
32067
32069
32070 this.isSkinnedMesh = true;
32071
32072 this.type = 'SkinnedMesh';
32073
32075 this.bindMatrix = new Matrix4();
32076 this.bindMatrixInverse = new Matrix4();
32077
32078 this.boundingBox = null;
32079 this.boundingSphere = null;
32080
32081 }
32082
32084
32085 const geometry = this.geometry;
32086
32087 if ( this.boundingBox === null ) {
32088
32089 this.boundingBox = new Box3();
32090
32091 }
32092
32093 this.boundingBox.makeEmpty();
32094
32095 const positionAttribute = geometry.getAttribute( 'position' );
32096
32097 for ( let i = 0; i < positionAttribute.count; i ++ ) {
32098
32099 this.getVertexPosition( i, _vertex );
32100 this.boundingBox.expandByPoint( _vertex );
32101
32102 }
32103
32104 }
32105
32107
32108 const geometry = this.geometry;
32109
32110 if ( this.boundingSphere === null ) {
32111
32112 this.boundingSphere = new Sphere();
32113
32114 }
32115
32116 this.boundingSphere.makeEmpty();
32117
32118 const positionAttribute = geometry.getAttribute( 'position' );
32119
32120 for ( let i = 0; i < positionAttribute.count; i ++ ) {
32121
32122 this.getVertexPosition( i, _vertex );
32123 this.boundingSphere.expandByPoint( _vertex );
32124
32125 }
32126
32127 }
32128
32129 copy( source, recursive ) {
32130
32131 super.copy( source, recursive );
32132
32133 this.bindMode = source.bindMode;
32134 this.bindMatrix.copy( source.bindMatrix );
32135 this.bindMatrixInverse.copy( source.bindMatrixInverse );
32136
32137 this.skeleton = source.skeleton;
32138
32139 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32140 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32141
32142 return this;
32143
32144 }
32145
32147
32148 const material = this.material;
32149 const matrixWorld = this.matrixWorld;
32150
32151 if ( material === undefined ) return;
32152
32153 // test with bounding sphere in world space
32154
32155 if ( this.boundingSphere === null ) this.computeBoundingSphere();
32156
32157 _sphere$4.copy( this.boundingSphere );
32158 _sphere$4.applyMatrix4( matrixWorld );
32159
32160 if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return;
32161
32162 // convert ray to local space of skinned mesh
32163
32164 _inverseMatrix$2.copy( matrixWorld ).invert();
32165 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );
32166
32167 // test with bounding box in local space
32168
32169 if ( this.boundingBox !== null ) {
32170
32171 if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return;
32172
32173 }
32174
32175 // test for intersections with geometry
32176
32178
32179 }
32180
32181 getVertexPosition( index, target ) {
32182
32183 super.getVertexPosition( index, target );
32184
32185 this.applyBoneTransform( index, target );
32186
32187 return target;
32188
32189 }
32190
32192
32193 this.skeleton = skeleton;
32194
32195 if ( bindMatrix === undefined ) {
32196
32197 this.updateMatrixWorld( true );
32198
32199 this.skeleton.calculateInverses();
32200
32201 bindMatrix = this.matrixWorld;
32202
32203 }
32204
32205 this.bindMatrix.copy( bindMatrix );
32206 this.bindMatrixInverse.copy( bindMatrix ).invert();
32207
32208 }
32209
32210 pose() {
32211
32212 this.skeleton.pose();
32213
32214 }
32215
32217
32218 const vector = new Vector4();
32219
32220 const skinWeight = this.geometry.attributes.skinWeight;
32221
32222 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
32223
32224 vector.fromBufferAttribute( skinWeight, i );
32225
32226 const scale = 1.0 / vector.manhattanLength();
32227
32228 if ( scale !== Infinity ) {
32229
32230 vector.multiplyScalar( scale );
32231
32232 } else {
32233
32234 vector.set( 1, 0, 0, 0 ); // do something reasonable
32235
32236 }
32237
32238 skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
32239
32240 }
32241
32242 }
32243
32245
32246 super.updateMatrixWorld( force );
32247
32248 if ( this.bindMode === AttachedBindMode ) {
32249
32250 this.bindMatrixInverse.copy( this.matrixWorld ).invert();
32251
32252 } else if ( this.bindMode === DetachedBindMode ) {
32253
32254 this.bindMatrixInverse.copy( this.bindMatrix ).invert();
32255
32256 } else {
32257
32258 console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
32259
32260 }
32261
32262 }
32263
32264 applyBoneTransform( index, vector ) {
32265
32266 const skeleton = this.skeleton;
32267 const geometry = this.geometry;
32268
32269 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
32270 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
32271
32272 _basePosition.copy( vector ).applyMatrix4( this.bindMatrix );
32273
32274 vector.set( 0, 0, 0 );
32275
32276 for ( let i = 0; i < 4; i ++ ) {
32277
32278 const weight = _skinWeight.getComponent( i );
32279
32280 if ( weight !== 0 ) {
32281
32282 const boneIndex = _skinIndex.getComponent( i );
32283
32284 _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
32285
32286 vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );
32287
32288 }
32289
32290 }
32291
32292 return vector.applyMatrix4( this.bindMatrixInverse );
32293
32294 }
32295
32296 boneTransform( index, vector ) { // @deprecated, r151
32297
32298 console.warn( 'THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151.' );
32299 return this.applyBoneTransform( index, vector );
32300
32301 }
32302
32303
32304 }
32305
32306 class Bone extends Object3D {
32307
32308 constructor() {
32309
32310 super();
32311
32312 this.isBone = true;
32313
32314 this.type = 'Bone';
32315
32316 }
32317
32318 }
32319
32320 class DataTexture extends Texture {
32321
32323
32324 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
32325
32326 this.isDataTexture = true;
32327
32328 this.image = { data: data, width: width, height: height };
32329
32330 this.generateMipmaps = false;
32331 this.flipY = false;
32332 this.unpackAlignment = 1;
32333
32334 }
32335
32336 }
32337
32338 const _offsetMatrix = /*@__PURE__*/ new Matrix4();
32339 const _identityMatrix$1 = /*@__PURE__*/ new Matrix4();
32340
32341 class Skeleton {
32342
32343 constructor( bones = [], boneInverses = [] ) {
32344
32345 this.uuid = generateUUID();
32346
32347 this.bones = bones.slice( 0 );
32349 this.boneMatrices = null;
32350
32351 this.boneTexture = null;
32352
32353 this.init();
32354
32355 }
32356
32357 init() {
32358
32359 const bones = this.bones;
32360 const boneInverses = this.boneInverses;
32361
32362 this.boneMatrices = new Float32Array( bones.length * 16 );
32363
32364 // calculate inverse bone matrices if necessary
32365
32366 if ( boneInverses.length === 0 ) {
32367
32368 this.calculateInverses();
32369
32370 } else {
32371
32372 // handle special case
32373
32374 if ( bones.length !== boneInverses.length ) {
32375
32376 console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );
32377
32378 this.boneInverses = [];
32379
32380 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32381
32382 this.boneInverses.push( new Matrix4() );
32383
32384 }
32385
32386 }
32387
32388 }
32389
32390 }
32391
32393
32394 this.boneInverses.length = 0;
32395
32396 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32397
32398 const inverse = new Matrix4();
32399
32400 if ( this.bones[ i ] ) {
32401
32402 inverse.copy( this.bones[ i ].matrixWorld ).invert();
32403
32404 }
32405
32406 this.boneInverses.push( inverse );
32407
32408 }
32409
32410 }
32411
32412 pose() {
32413
32414 // recover the bind-time world matrices
32415
32416 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32417
32418 const bone = this.bones[ i ];
32419
32420 if ( bone ) {
32421
32422 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert();
32423
32424 }
32425
32426 }
32427
32428 // compute the local matrices, positions, rotations and scales
32429
32430 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32431
32432 const bone = this.bones[ i ];
32433
32434 if ( bone ) {
32435
32436 if ( bone.parent && bone.parent.isBone ) {
32437
32438 bone.matrix.copy( bone.parent.matrixWorld ).invert();
32439 bone.matrix.multiply( bone.matrixWorld );
32440
32441 } else {
32442
32443 bone.matrix.copy( bone.matrixWorld );
32444
32445 }
32446
32447 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
32448
32449 }
32450
32451 }
32452
32453 }
32454
32455 update() {
32456
32457 const bones = this.bones;
32458 const boneInverses = this.boneInverses;
32459 const boneMatrices = this.boneMatrices;
32460 const boneTexture = this.boneTexture;
32461
32462 // flatten bone matrices to array
32463
32464 for ( let i = 0, il = bones.length; i < il; i ++ ) {
32465
32466 // compute the offset between the current and the original transform
32467
32468 const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1;
32469
32470 _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );
32471 _offsetMatrix.toArray( boneMatrices, i * 16 );
32472
32473 }
32474
32475 if ( boneTexture !== null ) {
32476
32477 boneTexture.needsUpdate = true;
32478
32479 }
32480
32481 }
32482
32483 clone() {
32484
32485 return new Skeleton( this.bones, this.boneInverses );
32486
32487 }
32488
32490
32491 // layout (1 matrix = 4 pixels)
32492 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
32493 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
32494 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
32495 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
32496 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
32497
32498 let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix
32499 size = Math.ceil( size / 4 ) * 4;
32500 size = Math.max( size, 4 );
32501
32502 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
32503 boneMatrices.set( this.boneMatrices ); // copy current values
32504
32506 boneTexture.needsUpdate = true;
32507
32509 this.boneTexture = boneTexture;
32510
32511 return this;
32512
32513 }
32514
32515 getBoneByName( name ) {
32516
32517 for ( let i = 0, il = this.bones.length; i < il; i ++ ) {
32518
32519 const bone = this.bones[ i ];
32520
32521 if ( bone.name === name ) {
32522
32523 return bone;
32524
32525 }
32526
32527 }
32528
32529 return undefined;
32530
32531 }
32532
32533 dispose( ) {
32534
32535 if ( this.boneTexture !== null ) {
32536
32537 this.boneTexture.dispose();
32538
32539 this.boneTexture = null;
32540
32541 }
32542
32543 }
32544
32545 fromJSON( json, bones ) {
32546
32547 this.uuid = json.uuid;
32548
32549 for ( let i = 0, l = json.bones.length; i < l; i ++ ) {
32550
32551 const uuid = json.bones[ i ];
32552 let bone = bones[ uuid ];
32553
32554 if ( bone === undefined ) {
32555
32556 console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );
32557 bone = new Bone();
32558
32559 }
32560
32561 this.bones.push( bone );
32562 this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );
32563
32564 }
32565
32566 this.init();
32567
32568 return this;
32569
32570 }
32571
32572 toJSON() {
32573
32574 const data = {
32575 metadata: {
32576 version: 4.6,
32577 type: 'Skeleton',
32578 generator: 'Skeleton.toJSON'
32579 },
32580 bones: [],
32581 boneInverses: []
32582 };
32583
32584 data.uuid = this.uuid;
32585
32586 const bones = this.bones;
32587 const boneInverses = this.boneInverses;
32588
32589 for ( let i = 0, l = bones.length; i < l; i ++ ) {
32590
32591 const bone = bones[ i ];
32592 data.bones.push( bone.uuid );
32593
32594 const boneInverse = boneInverses[ i ];
32595 data.boneInverses.push( boneInverse.toArray() );
32596
32597 }
32598
32599 return data;
32600
32601 }
32602
32603 }
32604
32606
32608
32610
32611 this.isInstancedBufferAttribute = true;
32612
32614
32615 }
32616
32617 copy( source ) {
32618
32619 super.copy( source );
32620
32621 this.meshPerAttribute = source.meshPerAttribute;
32622
32623 return this;
32624
32625 }
32626
32627 toJSON() {
32628
32629 const data = super.toJSON();
32630
32631 data.meshPerAttribute = this.meshPerAttribute;
32632
32633 data.isInstancedBufferAttribute = true;
32634
32635 return data;
32636
32637 }
32638
32639 }
32640
32641 const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();
32642 const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();
32643
32644 const _instanceIntersects = [];
32645
32646 const _box3 = /*@__PURE__*/ new Box3();
32647 const _identity = /*@__PURE__*/ new Matrix4();
32648 const _mesh$1 = /*@__PURE__*/ new Mesh();
32649 const _sphere$3 = /*@__PURE__*/ new Sphere();
32650
32651 class InstancedMesh extends Mesh {
32652
32653 constructor( geometry, material, count ) {
32654
32656
32657 this.isInstancedMesh = true;
32658
32659 this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );
32660 this.instanceColor = null;
32661
32662 this.count = count;
32663
32664 this.boundingBox = null;
32665 this.boundingSphere = null;
32666
32667 for ( let i = 0; i < count; i ++ ) {
32668
32669 this.setMatrixAt( i, _identity );
32670
32671 }
32672
32673 }
32674
32676
32677 const geometry = this.geometry;
32678 const count = this.count;
32679
32680 if ( this.boundingBox === null ) {
32681
32682 this.boundingBox = new Box3();
32683
32684 }
32685
32686 if ( geometry.boundingBox === null ) {
32687
32688 geometry.computeBoundingBox();
32689
32690 }
32691
32692 this.boundingBox.makeEmpty();
32693
32694 for ( let i = 0; i < count; i ++ ) {
32695
32697
32698 _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );
32699
32700 this.boundingBox.union( _box3 );
32701
32702 }
32703
32704 }
32705
32707
32708 const geometry = this.geometry;
32709 const count = this.count;
32710
32711 if ( this.boundingSphere === null ) {
32712
32713 this.boundingSphere = new Sphere();
32714
32715 }
32716
32717 if ( geometry.boundingSphere === null ) {
32718
32719 geometry.computeBoundingSphere();
32720
32721 }
32722
32723 this.boundingSphere.makeEmpty();
32724
32725 for ( let i = 0; i < count; i ++ ) {
32726
32728
32729 _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );
32730
32731 this.boundingSphere.union( _sphere$3 );
32732
32733 }
32734
32735 }
32736
32737 copy( source, recursive ) {
32738
32739 super.copy( source, recursive );
32740
32741 this.instanceMatrix.copy( source.instanceMatrix );
32742
32743 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();
32744
32745 this.count = source.count;
32746
32747 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();
32748 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
32749
32750 return this;
32751
32752 }
32753
32754 getColorAt( index, color ) {
32755
32756 color.fromArray( this.instanceColor.array, index * 3 );
32757
32758 }
32759
32761
32762 matrix.fromArray( this.instanceMatrix.array, index * 16 );
32763
32764 }
32765
32767
32768 const matrixWorld = this.matrixWorld;
32769 const raycastTimes = this.count;
32770
32771 _mesh$1.geometry = this.geometry;
32772 _mesh$1.material = this.material;
32773
32774 if ( _mesh$1.material === undefined ) return;
32775
32776 // test with bounding sphere first
32777
32778 if ( this.boundingSphere === null ) this.computeBoundingSphere();
32779
32780 _sphere$3.copy( this.boundingSphere );
32781 _sphere$3.applyMatrix4( matrixWorld );
32782
32783 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;
32784
32785 // now test each instance
32786
32787 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {
32788
32789 // calculate the world matrix for each instance
32790
32792
32793 _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );
32794
32795 // the mesh represents this single instance
32796
32797 _mesh$1.matrixWorld = _instanceWorldMatrix;
32798
32800
32801 // process the result of raycast
32802
32803 for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {
32804
32805 const intersect = _instanceIntersects[ i ];
32806 intersect.instanceId = instanceId;
32807 intersect.object = this;
32808 intersects.push( intersect );
32809
32810 }
32811
32812 _instanceIntersects.length = 0;
32813
32814 }
32815
32816 }
32817
32818 setColorAt( index, color ) {
32819
32820 if ( this.instanceColor === null ) {
32821
32822 this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 );
32823
32824 }
32825
32826 color.toArray( this.instanceColor.array, index * 3 );
32827
32828 }
32829
32831
32832 matrix.toArray( this.instanceMatrix.array, index * 16 );
32833
32834 }
32835
32837
32838 }
32839
32840 dispose() {
32841
32842 this.dispatchEvent( { type: 'dispose' } );
32843
32844 }
32845
32846 }
32847
32848 function sortOpaque( a, b ) {
32849
32850 return a.z - b.z;
32851
32852 }
32853
32854 function sortTransparent( a, b ) {
32855
32856 return b.z - a.z;
32857
32858 }
32859
32860 class MultiDrawRenderList {
32861
32862 constructor() {
32863
32864 this.index = 0;
32865 this.pool = [];
32866 this.list = [];
32867
32868 }
32869
32870 push( drawRange, z ) {
32871
32872 const pool = this.pool;
32873 const list = this.list;
32874 if ( this.index >= pool.length ) {
32875
32876 pool.push( {
32877
32878 start: - 1,
32879 count: - 1,
32880 z: - 1,
32881
32882 } );
32883
32884 }
32885
32886 const item = pool[ this.index ];
32887 list.push( item );
32888 this.index ++;
32889
32890 item.start = drawRange.start;
32891 item.count = drawRange.count;
32892 item.z = z;
32893
32894 }
32895
32896 reset() {
32897
32898 this.list.length = 0;
32899 this.index = 0;
32900
32901 }
32902
32903 }
32904
32905 const ID_ATTR_NAME = 'batchId';
32906 const _matrix = /*@__PURE__*/ new Matrix4();
32907 const _invMatrixWorld = /*@__PURE__*/ new Matrix4();
32908 const _identityMatrix = /*@__PURE__*/ new Matrix4();
32909 const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4();
32910 const _frustum = /*@__PURE__*/ new Frustum();
32911 const _box$1 = /*@__PURE__*/ new Box3();
32912 const _sphere$2 = /*@__PURE__*/ new Sphere();
32913 const _vector$5 = /*@__PURE__*/ new Vector3();
32914 const _renderList = /*@__PURE__*/ new MultiDrawRenderList();
32915 const _mesh = /*@__PURE__*/ new Mesh();
32916 const _batchIntersects = [];
32917
32918 // @TODO: SkinnedMesh support?
32919 // @TODO: geometry.groups support?
32920 // @TODO: geometry.drawRange support?
32921 // @TODO: geometry.morphAttributes support?
32922 // @TODO: Support uniform parameter per geometry
32923 // @TODO: Add an "optimize" function to pack geometry and remove data gaps
32924
32925 // copies data from attribute "src" into "target" starting at "targetOffset"
32926 function copyAttributeData( src, target, targetOffset = 0 ) {
32927
32928 const itemSize = target.itemSize;
32929 if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {
32930
32931 // use the component getters and setters if the array data cannot
32932 // be copied directly
32933 const vertexCount = src.count;
32934 for ( let i = 0; i < vertexCount; i ++ ) {
32935
32936 for ( let c = 0; c < itemSize; c ++ ) {
32937
32938 target.setComponent( i + targetOffset, c, src.getComponent( i, c ) );
32939
32940 }
32941
32942 }
32943
32944 } else {
32945
32946 // faster copy approach using typed array set function
32947 target.array.set( src.array, targetOffset * itemSize );
32948
32949 }
32950
32951 target.needsUpdate = true;
32952
32953 }
32954
32955 class BatchedMesh extends Mesh {
32956
32957 get maxGeometryCount() {
32958
32959 return this._maxGeometryCount;
32960
32961 }
32962
32964
32965 super( new BufferGeometry(), material );
32966
32967 this.isBatchedMesh = true;
32968 this.perObjectFrustumCulled = true;
32969 this.sortObjects = true;
32970 this.boundingBox = null;
32971 this.boundingSphere = null;
32972 this.customSort = null;
32973
32974 this._drawRanges = [];
32975 this._reservedRanges = [];
32976
32977 this._visibility = [];
32978 this._active = [];
32979 this._bounds = [];
32980
32984
32985 this._geometryInitialized = false;
32986 this._geometryCount = 0;
32989 this._multiDrawCount = 0;
32990 this._visibilityChanged = true;
32991
32992 // Local matrix per geometry by using data texture
32993 this._matricesTexture = null;
32994
32995 this._initMatricesTexture();
32996
32997 }
32998
33000
33001 // layout (1 matrix = 4 pixels)
33002 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
33003 // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8)
33004 // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16)
33005 // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32)
33006 // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)
33007
33008 let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
33009 size = Math.ceil( size / 4 ) * 4;
33010 size = Math.max( size, 4 );
33011
33012 const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
33014
33016
33017 }
33018
33020
33021 const geometry = this.geometry;
33022 const maxVertexCount = this._maxVertexCount;
33024 const maxIndexCount = this._maxIndexCount;
33025 if ( this._geometryInitialized === false ) {
33026
33027 for ( const attributeName in reference.attributes ) {
33028
33029 const srcAttribute = reference.getAttribute( attributeName );
33030 const { array, itemSize, normalized } = srcAttribute;
33031
33032 const dstArray = new array.constructor( maxVertexCount * itemSize );
33033 const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized );
33034 dstAttribute.setUsage( srcAttribute.usage );
33035
33036 geometry.setAttribute( attributeName, dstAttribute );
33037
33038 }
33039
33040 if ( reference.getIndex() !== null ) {
33041
33042 const indexArray = maxVertexCount > 65536
33043 ? new Uint32Array( maxIndexCount )
33045
33046 geometry.setIndex( new BufferAttribute( indexArray, 1 ) );
33047
33048 }
33049
33050 const idArray = maxGeometryCount > 65536
33053 geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );
33054
33055 this._geometryInitialized = true;
33056
33057 }
33058
33059 }
33060
33061 // Make sure the geometry is compatible with the existing combined geometry atributes
33062 _validateGeometry( geometry ) {
33063
33064 // check that the geometry doesn't have a version of our reserved id attribute
33065 if ( geometry.getAttribute( ID_ATTR_NAME ) ) {
33066
33067 throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` );
33068
33069 }
33070
33071 // check to ensure the geometries are using consistent attributes and indices
33072 const batchGeometry = this.geometry;
33073 if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {
33074
33075 throw new Error( 'BatchedMesh: All geometries must consistently have "index".' );
33076
33077 }
33078
33079 for ( const attributeName in batchGeometry.attributes ) {
33080
33081 if ( attributeName === ID_ATTR_NAME ) {
33082
33083 continue;
33084
33085 }
33086
33087 if ( ! geometry.hasAttribute( attributeName ) ) {
33088
33089 throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );
33090
33091 }
33092
33093 const srcAttribute = geometry.getAttribute( attributeName );
33094 const dstAttribute = batchGeometry.getAttribute( attributeName );
33095 if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {
33096
33097 throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );
33098
33099 }
33100
33101 }
33102
33103 }
33104
33105 setCustomSort( func ) {
33106
33107 this.customSort = func;
33108 return this;
33109
33110 }
33111
33113
33114 if ( this.boundingBox === null ) {
33115
33116 this.boundingBox = new Box3();
33117
33118 }
33119
33120 const geometryCount = this._geometryCount;
33121 const boundingBox = this.boundingBox;
33122 const active = this._active;
33123
33124 boundingBox.makeEmpty();
33125 for ( let i = 0; i < geometryCount; i ++ ) {
33126
33127 if ( active[ i ] === false ) continue;
33128
33129 this.getMatrixAt( i, _matrix );
33130 this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix );
33131 boundingBox.union( _box$1 );
33132
33133 }
33134
33135 }
33136
33138
33139 if ( this.boundingSphere === null ) {
33140
33141 this.boundingSphere = new Sphere();
33142
33143 }
33144
33145 const geometryCount = this._geometryCount;
33146 const boundingSphere = this.boundingSphere;
33147 const active = this._active;
33148
33149 boundingSphere.makeEmpty();
33150 for ( let i = 0; i < geometryCount; i ++ ) {
33151
33152 if ( active[ i ] === false ) continue;
33153
33154 this.getMatrixAt( i, _matrix );
33155 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33156 boundingSphere.union( _sphere$2 );
33157
33158 }
33159
33160 }
33161
33162 addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {
33163
33164 this._initializeGeometry( geometry );
33165
33166 this._validateGeometry( geometry );
33167
33168 // ensure we're not over geometry
33169 if ( this._geometryCount >= this._maxGeometryCount ) {
33170
33171 throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33172
33173 }
33174
33175 // get the necessary range fo the geometry
33176 const reservedRange = {
33177 vertexStart: - 1,
33178 vertexCount: - 1,
33179 indexStart: - 1,
33180 indexCount: - 1,
33181 };
33182
33183 let lastRange = null;
33184 const reservedRanges = this._reservedRanges;
33185 const drawRanges = this._drawRanges;
33186 const bounds = this._bounds;
33187 if ( this._geometryCount !== 0 ) {
33188
33189 lastRange = reservedRanges[ reservedRanges.length - 1 ];
33190
33191 }
33192
33193 if ( vertexCount === - 1 ) {
33194
33195 reservedRange.vertexCount = geometry.getAttribute( 'position' ).count;
33196
33197 } else {
33198
33199 reservedRange.vertexCount = vertexCount;
33200
33201 }
33202
33203 if ( lastRange === null ) {
33204
33205 reservedRange.vertexStart = 0;
33206
33207 } else {
33208
33209 reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;
33210
33211 }
33212
33213 const index = geometry.getIndex();
33214 const hasIndex = index !== null;
33215 if ( hasIndex ) {
33216
33217 if ( indexCount === - 1 ) {
33218
33219 reservedRange.indexCount = index.count;
33220
33221 } else {
33222
33223 reservedRange.indexCount = indexCount;
33224
33225 }
33226
33227 if ( lastRange === null ) {
33228
33229 reservedRange.indexStart = 0;
33230
33231 } else {
33232
33233 reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;
33234
33235 }
33236
33237 }
33238
33239 if (
33240 reservedRange.indexStart !== - 1 &&
33241 reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||
33242 reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount
33243 ) {
33244
33245 throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );
33246
33247 }
33248
33249 const visibility = this._visibility;
33250 const active = this._active;
33251 const matricesTexture = this._matricesTexture;
33252 const matricesArray = this._matricesTexture.image.data;
33253
33254 // push new visibility states
33255 visibility.push( true );
33256 active.push( true );
33257
33258 // update id
33259 const geometryId = this._geometryCount;
33260 this._geometryCount ++;
33261
33262 // initialize matrix information
33263 _identityMatrix.toArray( matricesArray, geometryId * 16 );
33264 matricesTexture.needsUpdate = true;
33265
33266 // add the reserved range and draw range objects
33268 drawRanges.push( {
33269 start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,
33270 count: - 1
33271 } );
33272 bounds.push( {
33273 boxInitialized: false,
33274 box: new Box3(),
33275
33276 sphereInitialized: false,
33277 sphere: new Sphere()
33278 } );
33279
33280 // set the id for the geometry
33281 const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME );
33282 for ( let i = 0; i < reservedRange.vertexCount; i ++ ) {
33283
33284 idAttribute.setX( reservedRange.vertexStart + i, geometryId );
33285
33286 }
33287
33288 idAttribute.needsUpdate = true;
33289
33290 // update the geometry
33291 this.setGeometryAt( geometryId, geometry );
33292
33293 return geometryId;
33294
33295 }
33296
33297 setGeometryAt( id, geometry ) {
33298
33299 if ( id >= this._geometryCount ) {
33300
33301 throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
33302
33303 }
33304
33305 this._validateGeometry( geometry );
33306
33307 const batchGeometry = this.geometry;
33308 const hasIndex = batchGeometry.getIndex() !== null;
33309 const dstIndex = batchGeometry.getIndex();
33310 const srcIndex = geometry.getIndex();
33311 const reservedRange = this._reservedRanges[ id ];
33312 if (
33313 hasIndex &&
33314 srcIndex.count > reservedRange.indexCount ||
33315 geometry.attributes.position.count > reservedRange.vertexCount
33316 ) {
33317
33318 throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );
33319
33320 }
33321
33322 // copy geometry over
33323 const vertexStart = reservedRange.vertexStart;
33324 const vertexCount = reservedRange.vertexCount;
33325 for ( const attributeName in batchGeometry.attributes ) {
33326
33327 if ( attributeName === ID_ATTR_NAME ) {
33328
33329 continue;
33330
33331 }
33332
33333 // copy attribute data
33334 const srcAttribute = geometry.getAttribute( attributeName );
33335 const dstAttribute = batchGeometry.getAttribute( attributeName );
33337
33338 // fill the rest in with zeroes
33339 const itemSize = srcAttribute.itemSize;
33340 for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {
33341
33342 const index = vertexStart + i;
33343 for ( let c = 0; c < itemSize; c ++ ) {
33344
33345 dstAttribute.setComponent( index, c, 0 );
33346
33347 }
33348
33349 }
33350
33351 dstAttribute.needsUpdate = true;
33352
33353 }
33354
33355 // copy index
33356 if ( hasIndex ) {
33357
33358 const indexStart = reservedRange.indexStart;
33359
33360 // copy index data over
33361 for ( let i = 0; i < srcIndex.count; i ++ ) {
33362
33363 dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );
33364
33365 }
33366
33367 // fill the rest in with zeroes
33368 for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {
33369
33370 dstIndex.setX( indexStart + i, vertexStart );
33371
33372 }
33373
33374 dstIndex.needsUpdate = true;
33375
33376 }
33377
33378 // store the bounding boxes
33379 const bound = this._bounds[ id ];
33380 if ( geometry.boundingBox !== null ) {
33381
33382 bound.box.copy( geometry.boundingBox );
33383 bound.boxInitialized = true;
33384
33385 } else {
33386
33387 bound.boxInitialized = false;
33388
33389 }
33390
33391 if ( geometry.boundingSphere !== null ) {
33392
33393 bound.sphere.copy( geometry.boundingSphere );
33394 bound.sphereInitialized = true;
33395
33396 } else {
33397
33398 bound.sphereInitialized = false;
33399
33400 }
33401
33402 // set drawRange count
33403 const drawRange = this._drawRanges[ id ];
33404 const posAttr = geometry.getAttribute( 'position' );
33405 drawRange.count = hasIndex ? srcIndex.count : posAttr.count;
33406 this._visibilityChanged = true;
33407
33408 return id;
33409
33410 }
33411
33413
33414 // Note: User needs to call optimize() afterward to pack the data.
33415
33416 const active = this._active;
33417 if ( geometryId >= active.length || active[ geometryId ] === false ) {
33418
33419 return this;
33420
33421 }
33422
33423 active[ geometryId ] = false;
33424 this._visibilityChanged = true;
33425
33426 return this;
33427
33428 }
33429
33430 // get bounding box and compute it if it doesn't exist
33431 getBoundingBoxAt( id, target ) {
33432
33433 const active = this._active;
33434 if ( active[ id ] === false ) {
33435
33436 return this;
33437
33438 }
33439
33440 // compute bounding box
33441 const bound = this._bounds[ id ];
33442 const box = bound.box;
33443 const geometry = this.geometry;
33444 if ( bound.boxInitialized === false ) {
33445
33446 box.makeEmpty();
33447
33448 const index = geometry.index;
33449 const position = geometry.attributes.position;
33450 const drawRange = this._drawRanges[ id ];
33451 for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33452
33453 let iv = i;
33454 if ( index ) {
33455
33456 iv = index.getX( iv );
33457
33458 }
33459
33460 box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) );
33461
33462 }
33463
33464 bound.boxInitialized = true;
33465
33466 }
33467
33468 target.copy( box );
33469 return target;
33470
33471 }
33472
33473 // get bounding sphere and compute it if it doesn't exist
33475
33476 const active = this._active;
33477 if ( active[ id ] === false ) {
33478
33479 return this;
33480
33481 }
33482
33483 // compute bounding sphere
33484 const bound = this._bounds[ id ];
33485 const sphere = bound.sphere;
33486 const geometry = this.geometry;
33487 if ( bound.sphereInitialized === false ) {
33488
33489 sphere.makeEmpty();
33490
33491 this.getBoundingBoxAt( id, _box$1 );
33492 _box$1.getCenter( sphere.center );
33493
33494 const index = geometry.index;
33495 const position = geometry.attributes.position;
33496 const drawRange = this._drawRanges[ id ];
33497
33498 let maxRadiusSq = 0;
33499 for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
33500
33501 let iv = i;
33502 if ( index ) {
33503
33504 iv = index.getX( iv );
33505
33506 }
33507
33508 _vector$5.fromBufferAttribute( position, iv );
33509 maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) );
33510
33511 }
33512
33513 sphere.radius = Math.sqrt( maxRadiusSq );
33514 bound.sphereInitialized = true;
33515
33516 }
33517
33518 target.copy( sphere );
33519 return target;
33520
33521 }
33522
33524
33525 // @TODO: Map geometryId to index of the arrays because
33526 // optimize() can make geometryId mismatch the index
33527
33528 const active = this._active;
33529 const matricesTexture = this._matricesTexture;
33530 const matricesArray = this._matricesTexture.image.data;
33531 const geometryCount = this._geometryCount;
33532 if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33533
33534 return this;
33535
33536 }
33537
33538 matrix.toArray( matricesArray, geometryId * 16 );
33539 matricesTexture.needsUpdate = true;
33540
33541 return this;
33542
33543 }
33544
33546
33547 const active = this._active;
33548 const matricesArray = this._matricesTexture.image.data;
33549 const geometryCount = this._geometryCount;
33550 if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33551
33552 return null;
33553
33554 }
33555
33556 return matrix.fromArray( matricesArray, geometryId * 16 );
33557
33558 }
33559
33561
33562 const visibility = this._visibility;
33563 const active = this._active;
33564 const geometryCount = this._geometryCount;
33565
33566 // if the geometry is out of range, not active, or visibility state
33567 // does not change then return early
33568 if (
33569 geometryId >= geometryCount ||
33570 active[ geometryId ] === false ||
33572 ) {
33573
33574 return this;
33575
33576 }
33577
33579 this._visibilityChanged = true;
33580
33581 return this;
33582
33583 }
33584
33586
33587 const visibility = this._visibility;
33588 const active = this._active;
33589 const geometryCount = this._geometryCount;
33590
33591 // return early if the geometry is out of range or not active
33592 if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
33593
33594 return false;
33595
33596 }
33597
33598 return visibility[ geometryId ];
33599
33600 }
33601
33603
33604 const visibility = this._visibility;
33605 const active = this._active;
33606 const drawRanges = this._drawRanges;
33607 const geometryCount = this._geometryCount;
33608 const matrixWorld = this.matrixWorld;
33609 const batchGeometry = this.geometry;
33610
33611 // iterate over each geometry
33612 _mesh.material = this.material;
33613 _mesh.geometry.index = batchGeometry.index;
33614 _mesh.geometry.attributes = batchGeometry.attributes;
33615 if ( _mesh.geometry.boundingBox === null ) {
33616
33617 _mesh.geometry.boundingBox = new Box3();
33618
33619 }
33620
33621 if ( _mesh.geometry.boundingSphere === null ) {
33622
33623 _mesh.geometry.boundingSphere = new Sphere();
33624
33625 }
33626
33627 for ( let i = 0; i < geometryCount; i ++ ) {
33628
33629 if ( ! visibility[ i ] || ! active[ i ] ) {
33630
33631 continue;
33632
33633 }
33634
33635 const drawRange = drawRanges[ i ];
33636 _mesh.geometry.setDrawRange( drawRange.start, drawRange.count );
33637
33638 // ge the intersects
33639 this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );
33640 this.getBoundingBoxAt( i, _mesh.geometry.boundingBox );
33641 this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere );
33642 _mesh.raycast( raycaster, _batchIntersects );
33643
33644 // add batch id to the intersects
33645 for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {
33646
33647 const intersect = _batchIntersects[ j ];
33648 intersect.object = this;
33649 intersect.batchId = i;
33650 intersects.push( intersect );
33651
33652 }
33653
33654 _batchIntersects.length = 0;
33655
33656 }
33657
33658 _mesh.material = null;
33659 _mesh.geometry.index = null;
33660 _mesh.geometry.attributes = {};
33661 _mesh.geometry.setDrawRange( 0, Infinity );
33662
33663 }
33664
33665 copy( source ) {
33666
33667 super.copy( source );
33668
33669 this.geometry = source.geometry.clone();
33670 this.perObjectFrustumCulled = source.perObjectFrustumCulled;
33671 this.sortObjects = source.sortObjects;
33672 this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
33673 this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
33674
33675 this._drawRanges = source._drawRanges.map( range => ( { ...range } ) );
33676 this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );
33677
33678 this._visibility = source._visibility.slice();
33679 this._active = source._active.slice();
33680 this._bounds = source._bounds.map( bound => ( {
33681 boxInitialized: bound.boxInitialized,
33682 box: bound.box.clone(),
33683
33686 } ) );
33687
33688 this._maxGeometryCount = source._maxGeometryCount;
33689 this._maxVertexCount = source._maxVertexCount;
33690 this._maxIndexCount = source._maxIndexCount;
33691
33692 this._geometryInitialized = source._geometryInitialized;
33693 this._geometryCount = source._geometryCount;
33694 this._multiDrawCounts = source._multiDrawCounts.slice();
33695 this._multiDrawStarts = source._multiDrawStarts.slice();
33696
33697 this._matricesTexture = source._matricesTexture.clone();
33698 this._matricesTexture.image.data = this._matricesTexture.image.slice();
33699
33700 return this;
33701
33702 }
33703
33704 dispose() {
33705
33706 // Assuming the geometry is not shared with other meshes
33707 this.geometry.dispose();
33708
33709 this._matricesTexture.dispose();
33710 this._matricesTexture = null;
33711 return this;
33712
33713 }
33714
33715 onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {
33716
33717 // if visibility has not changed and frustum culling and object sorting is not required
33718 // then skip iterating over all items
33719 if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {
33720
33721 return;
33722
33723 }
33724
33725 // the indexed version of the multi draw function requires specifying the start
33726 // offset in bytes.
33727 const index = geometry.getIndex();
33728 const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;
33729
33730 const visibility = this._visibility;
33731 const multiDrawStarts = this._multiDrawStarts;
33732 const multiDrawCounts = this._multiDrawCounts;
33733 const drawRanges = this._drawRanges;
33735
33736 // prepare the frustum in the local frame
33737 if ( perObjectFrustumCulled ) {
33738
33740 .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )
33741 .multiply( this.matrixWorld );
33742 _frustum.setFromProjectionMatrix(
33744 renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem
33745 );
33746
33747 }
33748
33749 let count = 0;
33750 if ( this.sortObjects ) {
33751
33752 // get the camera position in the local frame
33753 _invMatrixWorld.copy( this.matrixWorld ).invert();
33754 _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );
33755
33756 for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33757
33758 if ( visibility[ i ] ) {
33759
33760 // get the bounds in world space
33761 this.getMatrixAt( i, _matrix );
33762 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33763
33764 // determine whether the batched geometry is within the frustum
33765 let culled = false;
33766 if ( perObjectFrustumCulled ) {
33767
33768 culled = ! _frustum.intersectsSphere( _sphere$2 );
33769
33770 }
33771
33772 if ( ! culled ) {
33773
33774 // get the distance from camera used for sorting
33775 const z = _vector$5.distanceTo( _sphere$2.center );
33776 _renderList.push( drawRanges[ i ], z );
33777
33778 }
33779
33780 }
33781
33782 }
33783
33784 // Sort the draw ranges and prep for rendering
33785 const list = _renderList.list;
33786 const customSort = this.customSort;
33787 if ( customSort === null ) {
33788
33789 list.sort( material.transparent ? sortTransparent : sortOpaque );
33790
33791 } else {
33792
33793 customSort.call( this, list, camera );
33794
33795 }
33796
33797 for ( let i = 0, l = list.length; i < l; i ++ ) {
33798
33799 const item = list[ i ];
33801 multiDrawCounts[ count ] = item.count;
33802 count ++;
33803
33804 }
33805
33806 _renderList.reset();
33807
33808 } else {
33809
33810 for ( let i = 0, l = visibility.length; i < l; i ++ ) {
33811
33812 if ( visibility[ i ] ) {
33813
33814 // determine whether the batched geometry is within the frustum
33815 let culled = false;
33816 if ( perObjectFrustumCulled ) {
33817
33818 // get the bounds in world space
33819 this.getMatrixAt( i, _matrix );
33820 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix );
33821 culled = ! _frustum.intersectsSphere( _sphere$2 );
33822
33823 }
33824
33825 if ( ! culled ) {
33826
33827 const range = drawRanges[ i ];
33829 multiDrawCounts[ count ] = range.count;
33830 count ++;
33831
33832 }
33833
33834 }
33835
33836 }
33837
33838 }
33839
33840 this._multiDrawCount = count;
33841 this._visibilityChanged = false;
33842
33843 }
33844
33845 onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {
33846
33847 this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );
33848
33849 }
33850
33851 }
33852
33853 class LineBasicMaterial extends Material {
33854
33856
33857 super();
33858
33859 this.isLineBasicMaterial = true;
33860
33861 this.type = 'LineBasicMaterial';
33862
33863 this.color = new Color( 0xffffff );
33864
33865 this.map = null;
33866
33867 this.linewidth = 1;
33868 this.linecap = 'round';
33869 this.linejoin = 'round';
33870
33871 this.fog = true;
33872
33873 this.setValues( parameters );
33874
33875 }
33876
33877
33878 copy( source ) {
33879
33880 super.copy( source );
33881
33882 this.color.copy( source.color );
33883
33884 this.map = source.map;
33885
33886 this.linewidth = source.linewidth;
33887 this.linecap = source.linecap;
33888 this.linejoin = source.linejoin;
33889
33890 this.fog = source.fog;
33891
33892 return this;
33893
33894 }
33895
33896 }
33897
33898 const _start$1 = /*@__PURE__*/ new Vector3();
33899 const _end$1 = /*@__PURE__*/ new Vector3();
33900 const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();
33901 const _ray$1 = /*@__PURE__*/ new Ray();
33902 const _sphere$1 = /*@__PURE__*/ new Sphere();
33903
33904 class Line extends Object3D {
33905
33906 constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {
33907
33908 super();
33909
33910 this.isLine = true;
33911
33912 this.type = 'Line';
33913
33914 this.geometry = geometry;
33915 this.material = material;
33916
33917 this.updateMorphTargets();
33918
33919 }
33920
33921 copy( source, recursive ) {
33922
33923 super.copy( source, recursive );
33924
33925 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
33926 this.geometry = source.geometry;
33927
33928 return this;
33929
33930 }
33931
33933
33934 const geometry = this.geometry;
33935
33936 // we assume non-indexed geometry
33937
33938 if ( geometry.index === null ) {
33939
33940 const positionAttribute = geometry.attributes.position;
33941 const lineDistances = [ 0 ];
33942
33943 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {
33944
33945 _start$1.fromBufferAttribute( positionAttribute, i - 1 );
33946 _end$1.fromBufferAttribute( positionAttribute, i );
33947
33948 lineDistances[ i ] = lineDistances[ i - 1 ];
33949 lineDistances[ i ] += _start$1.distanceTo( _end$1 );
33950
33951 }
33952
33953 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
33954
33955 } else {
33956
33957 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
33958
33959 }
33960
33961 return this;
33962
33963 }
33964
33966
33967 const geometry = this.geometry;
33968 const matrixWorld = this.matrixWorld;
33969 const threshold = raycaster.params.Line.threshold;
33970 const drawRange = geometry.drawRange;
33971
33972 // Checking boundingSphere distance to ray
33973
33974 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
33975
33976 _sphere$1.copy( geometry.boundingSphere );
33977 _sphere$1.applyMatrix4( matrixWorld );
33978 _sphere$1.radius += threshold;
33979
33980 if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;
33981
33982 //
33983
33984 _inverseMatrix$1.copy( matrixWorld ).invert();
33985 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );
33986
33987 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
33989
33990 const vStart = new Vector3();
33991 const vEnd = new Vector3();
33992 const interSegment = new Vector3();
33993 const interRay = new Vector3();
33994 const step = this.isLineSegments ? 2 : 1;
33995
33996 const index = geometry.index;
33997 const attributes = geometry.attributes;
33998 const positionAttribute = attributes.position;
33999
34000 if ( index !== null ) {
34001
34002 const start = Math.max( 0, drawRange.start );
34003 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
34004
34005 for ( let i = start, l = end - 1; i < l; i += step ) {
34006
34007 const a = index.getX( i );
34008 const b = index.getX( i + 1 );
34009
34010 vStart.fromBufferAttribute( positionAttribute, a );
34011 vEnd.fromBufferAttribute( positionAttribute, b );
34012
34013 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34014
34015 if ( distSq > localThresholdSq ) continue;
34016
34017 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34018
34019 const distance = raycaster.ray.origin.distanceTo( interRay );
34020
34022
34023 intersects.push( {
34024
34026 // What do we want? intersection point on the ray or on the segment??
34027 // point: raycaster.ray.at( distance ),
34028 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34029 index: i,
34030 face: null,
34031 faceIndex: null,
34032 object: this
34033
34034 } );
34035
34036 }
34037
34038 } else {
34039
34040 const start = Math.max( 0, drawRange.start );
34041 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34042
34043 for ( let i = start, l = end - 1; i < l; i += step ) {
34044
34045 vStart.fromBufferAttribute( positionAttribute, i );
34046 vEnd.fromBufferAttribute( positionAttribute, i + 1 );
34047
34048 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment );
34049
34050 if ( distSq > localThresholdSq ) continue;
34051
34052 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation
34053
34054 const distance = raycaster.ray.origin.distanceTo( interRay );
34055
34057
34058 intersects.push( {
34059
34061 // What do we want? intersection point on the ray or on the segment??
34062 // point: raycaster.ray.at( distance ),
34063 point: interSegment.clone().applyMatrix4( this.matrixWorld ),
34064 index: i,
34065 face: null,
34066 faceIndex: null,
34067 object: this
34068
34069 } );
34070
34071 }
34072
34073 }
34074
34075 }
34076
34078
34079 const geometry = this.geometry;
34080
34081 const morphAttributes = geometry.morphAttributes;
34082 const keys = Object.keys( morphAttributes );
34083
34084 if ( keys.length > 0 ) {
34085
34086 const morphAttribute = morphAttributes[ keys[ 0 ] ];
34087
34088 if ( morphAttribute !== undefined ) {
34089
34090 this.morphTargetInfluences = [];
34091 this.morphTargetDictionary = {};
34092
34093 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34094
34095 const name = morphAttribute[ m ].name || String( m );
34096
34097 this.morphTargetInfluences.push( 0 );
34098 this.morphTargetDictionary[ name ] = m;
34099
34100 }
34101
34102 }
34103
34104 }
34105
34106 }
34107
34108 }
34109
34110 const _start = /*@__PURE__*/ new Vector3();
34111 const _end = /*@__PURE__*/ new Vector3();
34112
34113 class LineSegments extends Line {
34114
34115 constructor( geometry, material ) {
34116
34118
34119 this.isLineSegments = true;
34120
34121 this.type = 'LineSegments';
34122
34123 }
34124
34126
34127 const geometry = this.geometry;
34128
34129 // we assume non-indexed geometry
34130
34131 if ( geometry.index === null ) {
34132
34133 const positionAttribute = geometry.attributes.position;
34134 const lineDistances = [];
34135
34136 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {
34137
34138 _start.fromBufferAttribute( positionAttribute, i );
34139 _end.fromBufferAttribute( positionAttribute, i + 1 );
34140
34141 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];
34142 lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );
34143
34144 }
34145
34146 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );
34147
34148 } else {
34149
34150 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );
34151
34152 }
34153
34154 return this;
34155
34156 }
34157
34158 }
34159
34160 class LineLoop extends Line {
34161
34163
34165
34166 this.isLineLoop = true;
34167
34168 this.type = 'LineLoop';
34169
34170 }
34171
34172 }
34173
34174 class PointsMaterial extends Material {
34175
34177
34178 super();
34179
34180 this.isPointsMaterial = true;
34181
34182 this.type = 'PointsMaterial';
34183
34184 this.color = new Color( 0xffffff );
34185
34186 this.map = null;
34187
34188 this.alphaMap = null;
34189
34190 this.size = 1;
34191 this.sizeAttenuation = true;
34192
34193 this.fog = true;
34194
34195 this.setValues( parameters );
34196
34197 }
34198
34199 copy( source ) {
34200
34201 super.copy( source );
34202
34203 this.color.copy( source.color );
34204
34205 this.map = source.map;
34206
34207 this.alphaMap = source.alphaMap;
34208
34209 this.size = source.size;
34210 this.sizeAttenuation = source.sizeAttenuation;
34211
34212 this.fog = source.fog;
34213
34214 return this;
34215
34216 }
34217
34218 }
34219
34220 const _inverseMatrix = /*@__PURE__*/ new Matrix4();
34221 const _ray = /*@__PURE__*/ new Ray();
34222 const _sphere = /*@__PURE__*/ new Sphere();
34223 const _position$2 = /*@__PURE__*/ new Vector3();
34224
34225 class Points extends Object3D {
34226
34227 constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {
34228
34229 super();
34230
34231 this.isPoints = true;
34232
34233 this.type = 'Points';
34234
34235 this.geometry = geometry;
34236 this.material = material;
34237
34238 this.updateMorphTargets();
34239
34240 }
34241
34242 copy( source, recursive ) {
34243
34244 super.copy( source, recursive );
34245
34246 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
34247 this.geometry = source.geometry;
34248
34249 return this;
34250
34251 }
34252
34254
34255 const geometry = this.geometry;
34256 const matrixWorld = this.matrixWorld;
34257 const threshold = raycaster.params.Points.threshold;
34258 const drawRange = geometry.drawRange;
34259
34260 // Checking boundingSphere distance to ray
34261
34262 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
34263
34264 _sphere.copy( geometry.boundingSphere );
34265 _sphere.applyMatrix4( matrixWorld );
34266 _sphere.radius += threshold;
34267
34268 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
34269
34270 //
34271
34272 _inverseMatrix.copy( matrixWorld ).invert();
34273 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
34274
34275 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
34277
34278 const index = geometry.index;
34279 const attributes = geometry.attributes;
34280 const positionAttribute = attributes.position;
34281
34282 if ( index !== null ) {
34283
34284 const start = Math.max( 0, drawRange.start );
34285 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) );
34286
34287 for ( let i = start, il = end; i < il; i ++ ) {
34288
34289 const a = index.getX( i );
34290
34291 _position$2.fromBufferAttribute( positionAttribute, a );
34292
34294
34295 }
34296
34297 } else {
34298
34299 const start = Math.max( 0, drawRange.start );
34300 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );
34301
34302 for ( let i = start, l = end; i < l; i ++ ) {
34303
34304 _position$2.fromBufferAttribute( positionAttribute, i );
34305
34307
34308 }
34309
34310 }
34311
34312 }
34313
34315
34316 const geometry = this.geometry;
34317
34318 const morphAttributes = geometry.morphAttributes;
34319 const keys = Object.keys( morphAttributes );
34320
34321 if ( keys.length > 0 ) {
34322
34323 const morphAttribute = morphAttributes[ keys[ 0 ] ];
34324
34325 if ( morphAttribute !== undefined ) {
34326
34327 this.morphTargetInfluences = [];
34328 this.morphTargetDictionary = {};
34329
34330 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
34331
34332 const name = morphAttribute[ m ].name || String( m );
34333
34334 this.morphTargetInfluences.push( 0 );
34335 this.morphTargetDictionary[ name ] = m;
34336
34337 }
34338
34339 }
34340
34341 }
34342
34343 }
34344
34345 }
34346
34347 function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {
34348
34349 const rayPointDistanceSq = _ray.distanceSqToPoint( point );
34350
34352
34353 const intersectPoint = new Vector3();
34354
34355 _ray.closestPointToPoint( point, intersectPoint );
34356 intersectPoint.applyMatrix4( matrixWorld );
34357
34358 const distance = raycaster.ray.origin.distanceTo( intersectPoint );
34359
34361
34362 intersects.push( {
34363
34367 index: index,
34368 face: null,
34369 object: object
34370
34371 } );
34372
34373 }
34374
34375 }
34376
34377 class VideoTexture extends Texture {
34378
34380
34381 super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
34382
34383 this.isVideoTexture = true;
34384
34387
34388 this.generateMipmaps = false;
34389
34390 const scope = this;
34391
34392 function updateVideo() {
34393
34394 scope.needsUpdate = true;
34395 video.requestVideoFrameCallback( updateVideo );
34396
34397 }
34398
34399 if ( 'requestVideoFrameCallback' in video ) {
34400
34401 video.requestVideoFrameCallback( updateVideo );
34402
34403 }
34404
34405 }
34406
34407 clone() {
34408
34409 return new this.constructor( this.image ).copy( this );
34410
34411 }
34412
34413 update() {
34414
34415 const video = this.image;
34416 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
34417
34418 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
34419
34420 this.needsUpdate = true;
34421
34422 }
34423
34424 }
34425
34426 }
34427
34428 class FramebufferTexture extends Texture {
34429
34431
34432 super( { width, height } );
34433
34434 this.isFramebufferTexture = true;
34435
34436 this.magFilter = NearestFilter;
34437 this.minFilter = NearestFilter;
34438
34439 this.generateMipmaps = false;
34440
34441 this.needsUpdate = true;
34442
34443 }
34444
34445 }
34446
34447 class CompressedTexture extends Texture {
34448
34450
34451 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );
34452
34453 this.isCompressedTexture = true;
34454
34455 this.image = { width: width, height: height };
34456 this.mipmaps = mipmaps;
34457
34458 // no flipping for cube textures
34459 // (also flipping doesn't work for compressed textures )
34460
34461 this.flipY = false;
34462
34463 // can't generate mipmaps for compressed textures
34464 // mips must be embedded in DDS files
34465
34466 this.generateMipmaps = false;
34467
34468 }
34469
34470 }
34471
34473
34474 constructor( mipmaps, width, height, depth, format, type ) {
34475
34476 super( mipmaps, width, height, format, type );
34477
34478 this.isCompressedArrayTexture = true;
34479 this.image.depth = depth;
34481
34482 }
34483
34484 }
34485
34487
34488 constructor( images, format, type ) {
34489
34490 super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );
34491
34492 this.isCompressedCubeTexture = true;
34493 this.isCubeTexture = true;
34494
34495 this.image = images;
34496
34497 }
34498
34499 }
34500
34501 class CanvasTexture extends Texture {
34502
34504
34506
34507 this.isCanvasTexture = true;
34508
34509 this.needsUpdate = true;
34510
34511 }
34512
34513 }
34514
34545 class Curve {
34546
34547 constructor() {
34548
34549 this.type = 'Curve';
34550
34551 this.arcLengthDivisions = 200;
34552
34553 }
34554
34555 // Virtual base class method to overwrite and implement in subclasses
34556 // - t [0 .. 1]
34557
34558 getPoint( /* t, optionalTarget */ ) {
34559
34560 console.warn( 'THREE.Curve: .getPoint() not implemented.' );
34561 return null;
34562
34563 }
34564
34565 // Get point at relative position in curve according to arc length
34566 // - u [0 .. 1]
34567
34569
34570 const t = this.getUtoTmapping( u );
34571 return this.getPoint( t, optionalTarget );
34572
34573 }
34574
34575 // Get sequence of points using getPoint( t )
34576
34577 getPoints( divisions = 5 ) {
34578
34579 const points = [];
34580
34581 for ( let d = 0; d <= divisions; d ++ ) {
34582
34583 points.push( this.getPoint( d / divisions ) );
34584
34585 }
34586
34587 return points;
34588
34589 }
34590
34591 // Get sequence of points using getPointAt( u )
34592
34593 getSpacedPoints( divisions = 5 ) {
34594
34595 const points = [];
34596
34597 for ( let d = 0; d <= divisions; d ++ ) {
34598
34599 points.push( this.getPointAt( d / divisions ) );
34600
34601 }
34602
34603 return points;
34604
34605 }
34606
34607 // Get total curve arc length
34608
34609 getLength() {
34610
34611 const lengths = this.getLengths();
34612 return lengths[ lengths.length - 1 ];
34613
34614 }
34615
34616 // Get list of cumulative segment lengths
34617
34619
34620 if ( this.cacheArcLengths &&
34621 ( this.cacheArcLengths.length === divisions + 1 ) &&
34622 ! this.needsUpdate ) {
34623
34624 return this.cacheArcLengths;
34625
34626 }
34627
34628 this.needsUpdate = false;
34629
34630 const cache = [];
34631 let current, last = this.getPoint( 0 );
34632 let sum = 0;
34633
34634 cache.push( 0 );
34635
34636 for ( let p = 1; p <= divisions; p ++ ) {
34637
34638 current = this.getPoint( p / divisions );
34639 sum += current.distanceTo( last );
34640 cache.push( sum );
34641 last = current;
34642
34643 }
34644
34645 this.cacheArcLengths = cache;
34646
34647 return cache; // { sums: cache, sum: sum }; Sum is in the last element.
34648
34649 }
34650
34652
34653 this.needsUpdate = true;
34654 this.getLengths();
34655
34656 }
34657
34658 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant
34659
34660 getUtoTmapping( u, distance ) {
34661
34662 const arcLengths = this.getLengths();
34663
34664 let i = 0;
34665 const il = arcLengths.length;
34666
34667 let targetArcLength; // The targeted u distance value to get
34668
34669 if ( distance ) {
34670
34672
34673 } else {
34674
34675 targetArcLength = u * arcLengths[ il - 1 ];
34676
34677 }
34678
34679 // binary search for the index with largest value smaller than target u distance
34680
34681 let low = 0, high = il - 1, comparison;
34682
34683 while ( low <= high ) {
34684
34685 i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
34686
34688
34689 if ( comparison < 0 ) {
34690
34691 low = i + 1;
34692
34693 } else if ( comparison > 0 ) {
34694
34695 high = i - 1;
34696
34697 } else {
34698
34699 high = i;
34700 break;
34701
34702 // DONE
34703
34704 }
34705
34706 }
34707
34708 i = high;
34709
34710 if ( arcLengths[ i ] === targetArcLength ) {
34711
34712 return i / ( il - 1 );
34713
34714 }
34715
34716 // we could get finer grain at lengths, or use simple interpolation between two points
34717
34718 const lengthBefore = arcLengths[ i ];
34719 const lengthAfter = arcLengths[ i + 1 ];
34720
34722
34723 // determine where we are between the 'before' and 'after' points
34724
34726
34727 // add that fractional amount to t
34728
34729 const t = ( i + segmentFraction ) / ( il - 1 );
34730
34731 return t;
34732
34733 }
34734
34735 // Returns a unit vector tangent at t
34736 // In case any sub curve does not implement its tangent derivation,
34737 // 2 points a small delta apart will be used to find its gradient
34738 // which seems to give a reasonable approximation
34739
34741
34742 const delta = 0.0001;
34743 let t1 = t - delta;
34744 let t2 = t + delta;
34745
34746 // Capping in case of danger
34747
34748 if ( t1 < 0 ) t1 = 0;
34749 if ( t2 > 1 ) t2 = 1;
34750
34751 const pt1 = this.getPoint( t1 );
34752 const pt2 = this.getPoint( t2 );
34753
34754 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );
34755
34756 tangent.copy( pt2 ).sub( pt1 ).normalize();
34757
34758 return tangent;
34759
34760 }
34761
34763
34764 const t = this.getUtoTmapping( u );
34765 return this.getTangent( t, optionalTarget );
34766
34767 }
34768
34770
34771 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
34772
34773 const normal = new Vector3();
34774
34775 const tangents = [];
34776 const normals = [];
34777 const binormals = [];
34778
34779 const vec = new Vector3();
34780 const mat = new Matrix4();
34781
34782 // compute the tangent vectors for each segment on the curve
34783
34784 for ( let i = 0; i <= segments; i ++ ) {
34785
34786 const u = i / segments;
34787
34788 tangents[ i ] = this.getTangentAt( u, new Vector3() );
34789
34790 }
34791
34792 // select an initial normal vector perpendicular to the first tangent vector,
34793 // and in the direction of the minimum tangent xyz component
34794
34795 normals[ 0 ] = new Vector3();
34796 binormals[ 0 ] = new Vector3();
34797 let min = Number.MAX_VALUE;
34798 const tx = Math.abs( tangents[ 0 ].x );
34799 const ty = Math.abs( tangents[ 0 ].y );
34800 const tz = Math.abs( tangents[ 0 ].z );
34801
34802 if ( tx <= min ) {
34803
34804 min = tx;
34805 normal.set( 1, 0, 0 );
34806
34807 }
34808
34809 if ( ty <= min ) {
34810
34811 min = ty;
34812 normal.set( 0, 1, 0 );
34813
34814 }
34815
34816 if ( tz <= min ) {
34817
34818 normal.set( 0, 0, 1 );
34819
34820 }
34821
34822 vec.crossVectors( tangents[ 0 ], normal ).normalize();
34823
34824 normals[ 0 ].crossVectors( tangents[ 0 ], vec );
34825 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
34826
34827
34828 // compute the slowly-varying normal and binormal vectors for each segment on the curve
34829
34830 for ( let i = 1; i <= segments; i ++ ) {
34831
34832 normals[ i ] = normals[ i - 1 ].clone();
34833
34834 binormals[ i ] = binormals[ i - 1 ].clone();
34835
34836 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
34837
34838 if ( vec.length() > Number.EPSILON ) {
34839
34840 vec.normalize();
34841
34842 const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
34843
34844 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
34845
34846 }
34847
34848 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34849
34850 }
34851
34852 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
34853
34854 if ( closed === true ) {
34855
34856 let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
34857 theta /= segments;
34858
34859 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
34860
34861 theta = - theta;
34862
34863 }
34864
34865 for ( let i = 1; i <= segments; i ++ ) {
34866
34867 // twist a little...
34868 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
34869 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
34870
34871 }
34872
34873 }
34874
34875 return {
34879 };
34880
34881 }
34882
34883 clone() {
34884
34885 return new this.constructor().copy( this );
34886
34887 }
34888
34889 copy( source ) {
34890
34891 this.arcLengthDivisions = source.arcLengthDivisions;
34892
34893 return this;
34894
34895 }
34896
34897 toJSON() {
34898
34899 const data = {
34900 metadata: {
34901 version: 4.6,
34902 type: 'Curve',
34903 generator: 'Curve.toJSON'
34904 }
34905 };
34906
34907 data.arcLengthDivisions = this.arcLengthDivisions;
34908 data.type = this.type;
34909
34910 return data;
34911
34912 }
34913
34914 fromJSON( json ) {
34915
34916 this.arcLengthDivisions = json.arcLengthDivisions;
34917
34918 return this;
34919
34920 }
34921
34922 }
34923
34924 class EllipseCurve extends Curve {
34925
34926 constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {
34927
34928 super();
34929
34930 this.isEllipseCurve = true;
34931
34932 this.type = 'EllipseCurve';
34933
34934 this.aX = aX;
34935 this.aY = aY;
34936
34937 this.xRadius = xRadius;
34938 this.yRadius = yRadius;
34939
34940 this.aStartAngle = aStartAngle;
34941 this.aEndAngle = aEndAngle;
34942
34943 this.aClockwise = aClockwise;
34944
34945 this.aRotation = aRotation;
34946
34947 }
34948
34949 getPoint( t, optionalTarget ) {
34950
34951 const point = optionalTarget || new Vector2();
34952
34953 const twoPi = Math.PI * 2;
34954 let deltaAngle = this.aEndAngle - this.aStartAngle;
34955 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON;
34956
34957 // ensures that deltaAngle is 0 .. 2 PI
34958 while ( deltaAngle < 0 ) deltaAngle += twoPi;
34959 while ( deltaAngle > twoPi ) deltaAngle -= twoPi;
34960
34961 if ( deltaAngle < Number.EPSILON ) {
34962
34963 if ( samePoints ) {
34964
34965 deltaAngle = 0;
34966
34967 } else {
34968
34969 deltaAngle = twoPi;
34970
34971 }
34972
34973 }
34974
34975 if ( this.aClockwise === true && ! samePoints ) {
34976
34977 if ( deltaAngle === twoPi ) {
34978
34979 deltaAngle = - twoPi;
34980
34981 } else {
34982
34984
34985 }
34986
34987 }
34988
34989 const angle = this.aStartAngle + t * deltaAngle;
34990 let x = this.aX + this.xRadius * Math.cos( angle );
34991 let y = this.aY + this.yRadius * Math.sin( angle );
34992
34993 if ( this.aRotation !== 0 ) {
34994
34995 const cos = Math.cos( this.aRotation );
34996 const sin = Math.sin( this.aRotation );
34997
34998 const tx = x - this.aX;
34999 const ty = y - this.aY;
35000
35001 // Rotate the point about the center of the ellipse.
35002 x = tx * cos - ty * sin + this.aX;
35003 y = tx * sin + ty * cos + this.aY;
35004
35005 }
35006
35007 return point.set( x, y );
35008
35009 }
35010
35011 copy( source ) {
35012
35013 super.copy( source );
35014
35015 this.aX = source.aX;
35016 this.aY = source.aY;
35017
35018 this.xRadius = source.xRadius;
35019 this.yRadius = source.yRadius;
35020
35021 this.aStartAngle = source.aStartAngle;
35022 this.aEndAngle = source.aEndAngle;
35023
35024 this.aClockwise = source.aClockwise;
35025
35026 this.aRotation = source.aRotation;
35027
35028 return this;
35029
35030 }
35031
35032 toJSON() {
35033
35034 const data = super.toJSON();
35035
35036 data.aX = this.aX;
35037 data.aY = this.aY;
35038
35039 data.xRadius = this.xRadius;
35040 data.yRadius = this.yRadius;
35041
35042 data.aStartAngle = this.aStartAngle;
35043 data.aEndAngle = this.aEndAngle;
35044
35045 data.aClockwise = this.aClockwise;
35046
35047 data.aRotation = this.aRotation;
35048
35049 return data;
35050
35051 }
35052
35053 fromJSON( json ) {
35054
35055 super.fromJSON( json );
35056
35057 this.aX = json.aX;
35058 this.aY = json.aY;
35059
35060 this.xRadius = json.xRadius;
35061 this.yRadius = json.yRadius;
35062
35063 this.aStartAngle = json.aStartAngle;
35064 this.aEndAngle = json.aEndAngle;
35065
35066 this.aClockwise = json.aClockwise;
35067
35068 this.aRotation = json.aRotation;
35069
35070 return this;
35071
35072 }
35073
35074 }
35075
35076 class ArcCurve extends EllipseCurve {
35077
35078 constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
35079
35081
35082 this.isArcCurve = true;
35083
35084 this.type = 'ArcCurve';
35085
35086 }
35087
35088 }
35089
35100 /*
35101 Based on an optimized c++ solution in
35102 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/
35103 - http://ideone.com/NoEbVM
35104
35105 This CubicPoly class could be used for reusing some variables and calculations,
35106 but for three.js curve use, it could be possible inlined and flatten into a single function call
35107 which can be placed in CurveUtils.
35108 */
35109
35110 function CubicPoly() {
35111
35112 let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
35113
35114 /*
35115 * Compute coefficients for a cubic polynomial
35116 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3
35117 * such that
35118 * p(0) = x0, p(1) = x1
35119 * and
35120 * p'(0) = t0, p'(1) = t1.
35121 */
35122 function init( x0, x1, t0, t1 ) {
35123
35124 c0 = x0;
35125 c1 = t0;
35126 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
35127 c3 = 2 * x0 - 2 * x1 + t0 + t1;
35128
35129 }
35130
35131 return {
35132
35133 initCatmullRom: function ( x0, x1, x2, x3, tension ) {
35134
35135 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );
35136
35137 },
35138
35139 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {
35140
35141 // compute tangents when parameterized in [t1,t2]
35142 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;
35143 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;
35144
35145 // rescale tangents for parametrization in [0,1]
35146 t1 *= dt1;
35147 t2 *= dt1;
35148
35149 init( x1, x2, t1, t2 );
35150
35151 },
35152
35153 calc: function ( t ) {
35154
35155 const t2 = t * t;
35156 const t3 = t2 * t;
35157 return c0 + c1 * t + c2 * t2 + c3 * t3;
35158
35159 }
35160
35161 };
35162
35163 }
35164
35165 //
35166
35167 const tmp = /*@__PURE__*/ new Vector3();
35168 const px = /*@__PURE__*/ new CubicPoly();
35169 const py = /*@__PURE__*/ new CubicPoly();
35170 const pz = /*@__PURE__*/ new CubicPoly();
35171
35172 class CatmullRomCurve3 extends Curve {
35173
35174 constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {
35175
35176 super();
35177
35178 this.isCatmullRomCurve3 = true;
35179
35180 this.type = 'CatmullRomCurve3';
35181
35182 this.points = points;
35183 this.closed = closed;
35184 this.curveType = curveType;
35185 this.tension = tension;
35186
35187 }
35188
35189 getPoint( t, optionalTarget = new Vector3() ) {
35190
35191 const point = optionalTarget;
35192
35193 const points = this.points;
35194 const l = points.length;
35195
35196 const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
35197 let intPoint = Math.floor( p );
35198 let weight = p - intPoint;
35199
35200 if ( this.closed ) {
35201
35202 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;
35203
35204 } else if ( weight === 0 && intPoint === l - 1 ) {
35205
35206 intPoint = l - 2;
35207 weight = 1;
35208
35209 }
35210
35211 let p0, p3; // 4 points (p1 & p2 defined below)
35212
35213 if ( this.closed || intPoint > 0 ) {
35214
35215 p0 = points[ ( intPoint - 1 ) % l ];
35216
35217 } else {
35218
35219 // extrapolate first point
35220 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
35221 p0 = tmp;
35222
35223 }
35224
35225 const p1 = points[ intPoint % l ];
35226 const p2 = points[ ( intPoint + 1 ) % l ];
35227
35228 if ( this.closed || intPoint + 2 < l ) {
35229
35230 p3 = points[ ( intPoint + 2 ) % l ];
35231
35232 } else {
35233
35234 // extrapolate last point
35235 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );
35236 p3 = tmp;
35237
35238 }
35239
35240 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
35241
35242 // init Centripetal / Chordal Catmull-Rom
35243 const pow = this.curveType === 'chordal' ? 0.5 : 0.25;
35244 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
35245 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
35246 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
35247
35248 // safety check for repeated points
35249 if ( dt1 < 1e-4 ) dt1 = 1.0;
35250 if ( dt0 < 1e-4 ) dt0 = dt1;
35251 if ( dt2 < 1e-4 ) dt2 = dt1;
35252
35253 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );
35254 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
35255 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
35256
35257 } else if ( this.curveType === 'catmullrom' ) {
35258
35259 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
35260 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
35261 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
35262
35263 }
35264
35265 point.set(
35266 px.calc( weight ),
35267 py.calc( weight ),
35268 pz.calc( weight )
35269 );
35270
35271 return point;
35272
35273 }
35274
35275 copy( source ) {
35276
35277 super.copy( source );
35278
35279 this.points = [];
35280
35281 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35282
35283 const point = source.points[ i ];
35284
35285 this.points.push( point.clone() );
35286
35287 }
35288
35289 this.closed = source.closed;
35290 this.curveType = source.curveType;
35291 this.tension = source.tension;
35292
35293 return this;
35294
35295 }
35296
35297 toJSON() {
35298
35299 const data = super.toJSON();
35300
35301 data.points = [];
35302
35303 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35304
35305 const point = this.points[ i ];
35306 data.points.push( point.toArray() );
35307
35308 }
35309
35310 data.closed = this.closed;
35311 data.curveType = this.curveType;
35312 data.tension = this.tension;
35313
35314 return data;
35315
35316 }
35317
35318 fromJSON( json ) {
35319
35320 super.fromJSON( json );
35321
35322 this.points = [];
35323
35324 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35325
35326 const point = json.points[ i ];
35327 this.points.push( new Vector3().fromArray( point ) );
35328
35329 }
35330
35331 this.closed = json.closed;
35332 this.curveType = json.curveType;
35333 this.tension = json.tension;
35334
35335 return this;
35336
35337 }
35338
35339 }
35340
35346 function CatmullRom( t, p0, p1, p2, p3 ) {
35347
35348 const v0 = ( p2 - p0 ) * 0.5;
35349 const v1 = ( p3 - p1 ) * 0.5;
35350 const t2 = t * t;
35351 const t3 = t * t2;
35352 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
35353
35354 }
35355
35356 //
35357
35358 function QuadraticBezierP0( t, p ) {
35359
35360 const k = 1 - t;
35361 return k * k * p;
35362
35363 }
35364
35365 function QuadraticBezierP1( t, p ) {
35366
35367 return 2 * ( 1 - t ) * t * p;
35368
35369 }
35370
35371 function QuadraticBezierP2( t, p ) {
35372
35373 return t * t * p;
35374
35375 }
35376
35377 function QuadraticBezier( t, p0, p1, p2 ) {
35378
35379 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +
35381
35382 }
35383
35384 //
35385
35386 function CubicBezierP0( t, p ) {
35387
35388 const k = 1 - t;
35389 return k * k * k * p;
35390
35391 }
35392
35393 function CubicBezierP1( t, p ) {
35394
35395 const k = 1 - t;
35396 return 3 * k * k * t * p;
35397
35398 }
35399
35400 function CubicBezierP2( t, p ) {
35401
35402 return 3 * ( 1 - t ) * t * t * p;
35403
35404 }
35405
35406 function CubicBezierP3( t, p ) {
35407
35408 return t * t * t * p;
35409
35410 }
35411
35412 function CubicBezier( t, p0, p1, p2, p3 ) {
35413
35414 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +
35415 CubicBezierP3( t, p3 );
35416
35417 }
35418
35419 class CubicBezierCurve extends Curve {
35420
35421 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {
35422
35423 super();
35424
35425 this.isCubicBezierCurve = true;
35426
35427 this.type = 'CubicBezierCurve';
35428
35429 this.v0 = v0;
35430 this.v1 = v1;
35431 this.v2 = v2;
35432 this.v3 = v3;
35433
35434 }
35435
35436 getPoint( t, optionalTarget = new Vector2() ) {
35437
35438 const point = optionalTarget;
35439
35440 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35441
35442 point.set(
35443 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35444 CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
35445 );
35446
35447 return point;
35448
35449 }
35450
35451 copy( source ) {
35452
35453 super.copy( source );
35454
35455 this.v0.copy( source.v0 );
35456 this.v1.copy( source.v1 );
35457 this.v2.copy( source.v2 );
35458 this.v3.copy( source.v3 );
35459
35460 return this;
35461
35462 }
35463
35464 toJSON() {
35465
35466 const data = super.toJSON();
35467
35468 data.v0 = this.v0.toArray();
35469 data.v1 = this.v1.toArray();
35470 data.v2 = this.v2.toArray();
35471 data.v3 = this.v3.toArray();
35472
35473 return data;
35474
35475 }
35476
35477 fromJSON( json ) {
35478
35479 super.fromJSON( json );
35480
35481 this.v0.fromArray( json.v0 );
35482 this.v1.fromArray( json.v1 );
35483 this.v2.fromArray( json.v2 );
35484 this.v3.fromArray( json.v3 );
35485
35486 return this;
35487
35488 }
35489
35490 }
35491
35492 class CubicBezierCurve3 extends Curve {
35493
35494 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {
35495
35496 super();
35497
35498 this.isCubicBezierCurve3 = true;
35499
35500 this.type = 'CubicBezierCurve3';
35501
35502 this.v0 = v0;
35503 this.v1 = v1;
35504 this.v2 = v2;
35505 this.v3 = v3;
35506
35507 }
35508
35509 getPoint( t, optionalTarget = new Vector3() ) {
35510
35511 const point = optionalTarget;
35512
35513 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;
35514
35515 point.set(
35516 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
35517 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
35518 CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
35519 );
35520
35521 return point;
35522
35523 }
35524
35525 copy( source ) {
35526
35527 super.copy( source );
35528
35529 this.v0.copy( source.v0 );
35530 this.v1.copy( source.v1 );
35531 this.v2.copy( source.v2 );
35532 this.v3.copy( source.v3 );
35533
35534 return this;
35535
35536 }
35537
35538 toJSON() {
35539
35540 const data = super.toJSON();
35541
35542 data.v0 = this.v0.toArray();
35543 data.v1 = this.v1.toArray();
35544 data.v2 = this.v2.toArray();
35545 data.v3 = this.v3.toArray();
35546
35547 return data;
35548
35549 }
35550
35551 fromJSON( json ) {
35552
35553 super.fromJSON( json );
35554
35555 this.v0.fromArray( json.v0 );
35556 this.v1.fromArray( json.v1 );
35557 this.v2.fromArray( json.v2 );
35558 this.v3.fromArray( json.v3 );
35559
35560 return this;
35561
35562 }
35563
35564 }
35565
35566 class LineCurve extends Curve {
35567
35568 constructor( v1 = new Vector2(), v2 = new Vector2() ) {
35569
35570 super();
35571
35572 this.isLineCurve = true;
35573
35574 this.type = 'LineCurve';
35575
35576 this.v1 = v1;
35577 this.v2 = v2;
35578
35579 }
35580
35581 getPoint( t, optionalTarget = new Vector2() ) {
35582
35583 const point = optionalTarget;
35584
35585 if ( t === 1 ) {
35586
35587 point.copy( this.v2 );
35588
35589 } else {
35590
35591 point.copy( this.v2 ).sub( this.v1 );
35592 point.multiplyScalar( t ).add( this.v1 );
35593
35594 }
35595
35596 return point;
35597
35598 }
35599
35600 // Line curve is linear, so we can overwrite default getPointAt
35602
35603 return this.getPoint( u, optionalTarget );
35604
35605 }
35606
35607 getTangent( t, optionalTarget = new Vector2() ) {
35608
35609 return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35610
35611 }
35612
35614
35615 return this.getTangent( u, optionalTarget );
35616
35617 }
35618
35619 copy( source ) {
35620
35621 super.copy( source );
35622
35623 this.v1.copy( source.v1 );
35624 this.v2.copy( source.v2 );
35625
35626 return this;
35627
35628 }
35629
35630 toJSON() {
35631
35632 const data = super.toJSON();
35633
35634 data.v1 = this.v1.toArray();
35635 data.v2 = this.v2.toArray();
35636
35637 return data;
35638
35639 }
35640
35641 fromJSON( json ) {
35642
35643 super.fromJSON( json );
35644
35645 this.v1.fromArray( json.v1 );
35646 this.v2.fromArray( json.v2 );
35647
35648 return this;
35649
35650 }
35651
35652 }
35653
35654 class LineCurve3 extends Curve {
35655
35656 constructor( v1 = new Vector3(), v2 = new Vector3() ) {
35657
35658 super();
35659
35660 this.isLineCurve3 = true;
35661
35662 this.type = 'LineCurve3';
35663
35664 this.v1 = v1;
35665 this.v2 = v2;
35666
35667 }
35668
35669 getPoint( t, optionalTarget = new Vector3() ) {
35670
35671 const point = optionalTarget;
35672
35673 if ( t === 1 ) {
35674
35675 point.copy( this.v2 );
35676
35677 } else {
35678
35679 point.copy( this.v2 ).sub( this.v1 );
35680 point.multiplyScalar( t ).add( this.v1 );
35681
35682 }
35683
35684 return point;
35685
35686 }
35687
35688 // Line curve is linear, so we can overwrite default getPointAt
35690
35691 return this.getPoint( u, optionalTarget );
35692
35693 }
35694
35695 getTangent( t, optionalTarget = new Vector3() ) {
35696
35697 return optionalTarget.subVectors( this.v2, this.v1 ).normalize();
35698
35699 }
35700
35702
35703 return this.getTangent( u, optionalTarget );
35704
35705 }
35706
35707 copy( source ) {
35708
35709 super.copy( source );
35710
35711 this.v1.copy( source.v1 );
35712 this.v2.copy( source.v2 );
35713
35714 return this;
35715
35716 }
35717
35718 toJSON() {
35719
35720 const data = super.toJSON();
35721
35722 data.v1 = this.v1.toArray();
35723 data.v2 = this.v2.toArray();
35724
35725 return data;
35726
35727 }
35728
35729 fromJSON( json ) {
35730
35731 super.fromJSON( json );
35732
35733 this.v1.fromArray( json.v1 );
35734 this.v2.fromArray( json.v2 );
35735
35736 return this;
35737
35738 }
35739
35740 }
35741
35742 class QuadraticBezierCurve extends Curve {
35743
35744 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {
35745
35746 super();
35747
35748 this.isQuadraticBezierCurve = true;
35749
35750 this.type = 'QuadraticBezierCurve';
35751
35752 this.v0 = v0;
35753 this.v1 = v1;
35754 this.v2 = v2;
35755
35756 }
35757
35758 getPoint( t, optionalTarget = new Vector2() ) {
35759
35760 const point = optionalTarget;
35761
35762 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35763
35764 point.set(
35765 QuadraticBezier( t, v0.x, v1.x, v2.x ),
35766 QuadraticBezier( t, v0.y, v1.y, v2.y )
35767 );
35768
35769 return point;
35770
35771 }
35772
35773 copy( source ) {
35774
35775 super.copy( source );
35776
35777 this.v0.copy( source.v0 );
35778 this.v1.copy( source.v1 );
35779 this.v2.copy( source.v2 );
35780
35781 return this;
35782
35783 }
35784
35785 toJSON() {
35786
35787 const data = super.toJSON();
35788
35789 data.v0 = this.v0.toArray();
35790 data.v1 = this.v1.toArray();
35791 data.v2 = this.v2.toArray();
35792
35793 return data;
35794
35795 }
35796
35797 fromJSON( json ) {
35798
35799 super.fromJSON( json );
35800
35801 this.v0.fromArray( json.v0 );
35802 this.v1.fromArray( json.v1 );
35803 this.v2.fromArray( json.v2 );
35804
35805 return this;
35806
35807 }
35808
35809 }
35810
35811 class QuadraticBezierCurve3 extends Curve {
35812
35813 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {
35814
35815 super();
35816
35817 this.isQuadraticBezierCurve3 = true;
35818
35819 this.type = 'QuadraticBezierCurve3';
35820
35821 this.v0 = v0;
35822 this.v1 = v1;
35823 this.v2 = v2;
35824
35825 }
35826
35827 getPoint( t, optionalTarget = new Vector3() ) {
35828
35829 const point = optionalTarget;
35830
35831 const v0 = this.v0, v1 = this.v1, v2 = this.v2;
35832
35833 point.set(
35834 QuadraticBezier( t, v0.x, v1.x, v2.x ),
35835 QuadraticBezier( t, v0.y, v1.y, v2.y ),
35836 QuadraticBezier( t, v0.z, v1.z, v2.z )
35837 );
35838
35839 return point;
35840
35841 }
35842
35843 copy( source ) {
35844
35845 super.copy( source );
35846
35847 this.v0.copy( source.v0 );
35848 this.v1.copy( source.v1 );
35849 this.v2.copy( source.v2 );
35850
35851 return this;
35852
35853 }
35854
35855 toJSON() {
35856
35857 const data = super.toJSON();
35858
35859 data.v0 = this.v0.toArray();
35860 data.v1 = this.v1.toArray();
35861 data.v2 = this.v2.toArray();
35862
35863 return data;
35864
35865 }
35866
35867 fromJSON( json ) {
35868
35869 super.fromJSON( json );
35870
35871 this.v0.fromArray( json.v0 );
35872 this.v1.fromArray( json.v1 );
35873 this.v2.fromArray( json.v2 );
35874
35875 return this;
35876
35877 }
35878
35879 }
35880
35881 class SplineCurve extends Curve {
35882
35883 constructor( points = [] ) {
35884
35885 super();
35886
35887 this.isSplineCurve = true;
35888
35889 this.type = 'SplineCurve';
35890
35891 this.points = points;
35892
35893 }
35894
35895 getPoint( t, optionalTarget = new Vector2() ) {
35896
35897 const point = optionalTarget;
35898
35899 const points = this.points;
35900 const p = ( points.length - 1 ) * t;
35901
35902 const intPoint = Math.floor( p );
35903 const weight = p - intPoint;
35904
35905 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];
35906 const p1 = points[ intPoint ];
35907 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
35908 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
35909
35910 point.set(
35911 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
35912 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
35913 );
35914
35915 return point;
35916
35917 }
35918
35919 copy( source ) {
35920
35921 super.copy( source );
35922
35923 this.points = [];
35924
35925 for ( let i = 0, l = source.points.length; i < l; i ++ ) {
35926
35927 const point = source.points[ i ];
35928
35929 this.points.push( point.clone() );
35930
35931 }
35932
35933 return this;
35934
35935 }
35936
35937 toJSON() {
35938
35939 const data = super.toJSON();
35940
35941 data.points = [];
35942
35943 for ( let i = 0, l = this.points.length; i < l; i ++ ) {
35944
35945 const point = this.points[ i ];
35946 data.points.push( point.toArray() );
35947
35948 }
35949
35950 return data;
35951
35952 }
35953
35954 fromJSON( json ) {
35955
35956 super.fromJSON( json );
35957
35958 this.points = [];
35959
35960 for ( let i = 0, l = json.points.length; i < l; i ++ ) {
35961
35962 const point = json.points[ i ];
35963 this.points.push( new Vector2().fromArray( point ) );
35964
35965 }
35966
35967 return this;
35968
35969 }
35970
35971 }
35972
35973 var Curves = /*#__PURE__*/Object.freeze({
35974 __proto__: null,
35985 });
35986
35987 /**************************************************************
35988 * Curved Path - a curve path is simply a array of connected
35989 * curves, but retains the api of a curve
35990 **************************************************************/
35991
35992 class CurvePath extends Curve {
35993
35994 constructor() {
35995
35996 super();
35997
35998 this.type = 'CurvePath';
35999
36000 this.curves = [];
36001 this.autoClose = false; // Automatically closes the path
36002
36003 }
36004
36005 add( curve ) {
36006
36007 this.curves.push( curve );
36008
36009 }
36010
36011 closePath() {
36012
36013 // Add a line curve if start and end of lines are not connected
36014 const startPoint = this.curves[ 0 ].getPoint( 0 );
36015 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
36016
36017 if ( ! startPoint.equals( endPoint ) ) {
36018
36019 const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';
36020 this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );
36021
36022 }
36023
36024 return this;
36025
36026 }
36027
36028 // To get accurate point with reference to
36029 // entire path distance at time t,
36030 // following has to be done:
36031
36032 // 1. Length of each sub path have to be known
36033 // 2. Locate and identify type of curve
36034 // 3. Get t for the curve
36035 // 4. Return curve.getPointAt(t')
36036
36038
36039 const d = t * this.getLength();
36040 const curveLengths = this.getCurveLengths();
36041 let i = 0;
36042
36043 // To think about boundaries points.
36044
36045 while ( i < curveLengths.length ) {
36046
36047 if ( curveLengths[ i ] >= d ) {
36048
36049 const diff = curveLengths[ i ] - d;
36050 const curve = this.curves[ i ];
36051
36052 const segmentLength = curve.getLength();
36053 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;
36054
36055 return curve.getPointAt( u, optionalTarget );
36056
36057 }
36058
36059 i ++;
36060
36061 }
36062
36063 return null;
36064
36065 // loop where sum != 0, sum > d , sum+1 <d
36066
36067 }
36068
36069 // We cannot use the default THREE.Curve getPoint() with getLength() because in
36070 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath
36071 // getPoint() depends on getLength
36072
36073 getLength() {
36074
36075 const lens = this.getCurveLengths();
36076 return lens[ lens.length - 1 ];
36077
36078 }
36079
36080 // cacheLengths must be recalculated.
36082
36083 this.needsUpdate = true;
36084 this.cacheLengths = null;
36085 this.getCurveLengths();
36086
36087 }
36088
36089 // Compute lengths and cache them
36090 // We cannot overwrite getLengths() because UtoT mapping uses it.
36091
36092 getCurveLengths() {
36093
36094 // We use cache values if curves and cache array are same length
36095
36096 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) {
36097
36098 return this.cacheLengths;
36099
36100 }
36101
36102 // Get length of sub-curve
36103 // Push sums into cached array
36104
36105 const lengths = [];
36106 let sums = 0;
36107
36108 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36109
36110 sums += this.curves[ i ].getLength();
36111 lengths.push( sums );
36112
36113 }
36114
36115 this.cacheLengths = lengths;
36116
36117 return lengths;
36118
36119 }
36120
36121 getSpacedPoints( divisions = 40 ) {
36122
36123 const points = [];
36124
36125 for ( let i = 0; i <= divisions; i ++ ) {
36126
36127 points.push( this.getPoint( i / divisions ) );
36128
36129 }
36130
36131 if ( this.autoClose ) {
36132
36133 points.push( points[ 0 ] );
36134
36135 }
36136
36137 return points;
36138
36139 }
36140
36141 getPoints( divisions = 12 ) {
36142
36143 const points = [];
36144 let last;
36145
36146 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) {
36147
36148 const curve = curves[ i ];
36149 const resolution = curve.isEllipseCurve ? divisions * 2
36150 : ( curve.isLineCurve || curve.isLineCurve3 ) ? 1
36152 : divisions;
36153
36154 const pts = curve.getPoints( resolution );
36155
36156 for ( let j = 0; j < pts.length; j ++ ) {
36157
36158 const point = pts[ j ];
36159
36160 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates
36161
36162 points.push( point );
36163 last = point;
36164
36165 }
36166
36167 }
36168
36169 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {
36170
36171 points.push( points[ 0 ] );
36172
36173 }
36174
36175 return points;
36176
36177 }
36178
36179 copy( source ) {
36180
36181 super.copy( source );
36182
36183 this.curves = [];
36184
36185 for ( let i = 0, l = source.curves.length; i < l; i ++ ) {
36186
36187 const curve = source.curves[ i ];
36188
36189 this.curves.push( curve.clone() );
36190
36191 }
36192
36193 this.autoClose = source.autoClose;
36194
36195 return this;
36196
36197 }
36198
36199 toJSON() {
36200
36201 const data = super.toJSON();
36202
36203 data.autoClose = this.autoClose;
36204 data.curves = [];
36205
36206 for ( let i = 0, l = this.curves.length; i < l; i ++ ) {
36207
36208 const curve = this.curves[ i ];
36209 data.curves.push( curve.toJSON() );
36210
36211 }
36212
36213 return data;
36214
36215 }
36216
36217 fromJSON( json ) {
36218
36219 super.fromJSON( json );
36220
36221 this.autoClose = json.autoClose;
36222 this.curves = [];
36223
36224 for ( let i = 0, l = json.curves.length; i < l; i ++ ) {
36225
36226 const curve = json.curves[ i ];
36227 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );
36228
36229 }
36230
36231 return this;
36232
36233 }
36234
36235 }
36236
36237 class Path extends CurvePath {
36238
36239 constructor( points ) {
36240
36241 super();
36242
36243 this.type = 'Path';
36244
36245 this.currentPoint = new Vector2();
36246
36247 if ( points ) {
36248
36249 this.setFromPoints( points );
36250
36251 }
36252
36253 }
36254
36256
36257 this.moveTo( points[ 0 ].x, points[ 0 ].y );
36258
36259 for ( let i = 1, l = points.length; i < l; i ++ ) {
36260
36261 this.lineTo( points[ i ].x, points[ i ].y );
36262
36263 }
36264
36265 return this;
36266
36267 }
36268
36269 moveTo( x, y ) {
36270
36271 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?
36272
36273 return this;
36274
36275 }
36276
36277 lineTo( x, y ) {
36278
36279 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );
36280 this.curves.push( curve );
36281
36282 this.currentPoint.set( x, y );
36283
36284 return this;
36285
36286 }
36287
36289
36290 const curve = new QuadraticBezierCurve(
36291 this.currentPoint.clone(),
36292 new Vector2( aCPx, aCPy ),
36293 new Vector2( aX, aY )
36294 );
36295
36296 this.curves.push( curve );
36297
36298 this.currentPoint.set( aX, aY );
36299
36300 return this;
36301
36302 }
36303
36305
36306 const curve = new CubicBezierCurve(
36307 this.currentPoint.clone(),
36308 new Vector2( aCP1x, aCP1y ),
36309 new Vector2( aCP2x, aCP2y ),
36310 new Vector2( aX, aY )
36311 );
36312
36313 this.curves.push( curve );
36314
36315 this.currentPoint.set( aX, aY );
36316
36317 return this;
36318
36319 }
36320
36321 splineThru( pts /*Array of Vector*/ ) {
36322
36323 const npts = [ this.currentPoint.clone() ].concat( pts );
36324
36325 const curve = new SplineCurve( npts );
36326 this.curves.push( curve );
36327
36328 this.currentPoint.copy( pts[ pts.length - 1 ] );
36329
36330 return this;
36331
36332 }
36333
36334 arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
36335
36336 const x0 = this.currentPoint.x;
36337 const y0 = this.currentPoint.y;
36338
36339 this.absarc( aX + x0, aY + y0, aRadius,
36341
36342 return this;
36343
36344 }
36345
36347
36348 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
36349
36350 return this;
36351
36352 }
36353
36355
36356 const x0 = this.currentPoint.x;
36357 const y0 = this.currentPoint.y;
36358
36360
36361 return this;
36362
36363 }
36364
36366
36368
36369 if ( this.curves.length > 0 ) {
36370
36371 // if a previous curve is present, attempt to join
36372 const firstPoint = curve.getPoint( 0 );
36373
36374 if ( ! firstPoint.equals( this.currentPoint ) ) {
36375
36376 this.lineTo( firstPoint.x, firstPoint.y );
36377
36378 }
36379
36380 }
36381
36382 this.curves.push( curve );
36383
36384 const lastPoint = curve.getPoint( 1 );
36385 this.currentPoint.copy( lastPoint );
36386
36387 return this;
36388
36389 }
36390
36391 copy( source ) {
36392
36393 super.copy( source );
36394
36395 this.currentPoint.copy( source.currentPoint );
36396
36397 return this;
36398
36399 }
36400
36401 toJSON() {
36402
36403 const data = super.toJSON();
36404
36405 data.currentPoint = this.currentPoint.toArray();
36406
36407 return data;
36408
36409 }
36410
36411 fromJSON( json ) {
36412
36413 super.fromJSON( json );
36414
36415 this.currentPoint.fromArray( json.currentPoint );
36416
36417 return this;
36418
36419 }
36420
36421 }
36422
36423 class LatheGeometry extends BufferGeometry {
36424
36425 constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {
36426
36427 super();
36428
36429 this.type = 'LatheGeometry';
36430
36431 this.parameters = {
36432 points: points,
36436 };
36437
36438 segments = Math.floor( segments );
36439
36440 // clamp phiLength so it's in range of [ 0, 2PI ]
36441
36442 phiLength = clamp( phiLength, 0, Math.PI * 2 );
36443
36444 // buffers
36445
36446 const indices = [];
36447 const vertices = [];
36448 const uvs = [];
36449 const initNormals = [];
36450 const normals = [];
36451
36452 // helper variables
36453
36454 const inverseSegments = 1.0 / segments;
36455 const vertex = new Vector3();
36456 const uv = new Vector2();
36457 const normal = new Vector3();
36458 const curNormal = new Vector3();
36459 const prevNormal = new Vector3();
36460 let dx = 0;
36461 let dy = 0;
36462
36463 // pre-compute normals for initial "meridian"
36464
36465 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36466
36467 switch ( j ) {
36468
36469 case 0: // special handling for 1st vertex on path
36470
36471 dx = points[ j + 1 ].x - points[ j ].x;
36472 dy = points[ j + 1 ].y - points[ j ].y;
36473
36474 normal.x = dy * 1.0;
36475 normal.y = - dx;
36476 normal.z = dy * 0.0;
36477
36478 prevNormal.copy( normal );
36479
36480 normal.normalize();
36481
36482 initNormals.push( normal.x, normal.y, normal.z );
36483
36484 break;
36485
36486 case ( points.length - 1 ): // special handling for last Vertex on path
36487
36489
36490 break;
36491
36492 default: // default handling for all vertices in between
36493
36494 dx = points[ j + 1 ].x - points[ j ].x;
36495 dy = points[ j + 1 ].y - points[ j ].y;
36496
36497 normal.x = dy * 1.0;
36498 normal.y = - dx;
36499 normal.z = dy * 0.0;
36500
36501 curNormal.copy( normal );
36502
36503 normal.x += prevNormal.x;
36504 normal.y += prevNormal.y;
36505 normal.z += prevNormal.z;
36506
36507 normal.normalize();
36508
36509 initNormals.push( normal.x, normal.y, normal.z );
36510
36511 prevNormal.copy( curNormal );
36512
36513 }
36514
36515 }
36516
36517 // generate vertices, uvs and normals
36518
36519 for ( let i = 0; i <= segments; i ++ ) {
36520
36521 const phi = phiStart + i * inverseSegments * phiLength;
36522
36523 const sin = Math.sin( phi );
36524 const cos = Math.cos( phi );
36525
36526 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
36527
36528 // vertex
36529
36530 vertex.x = points[ j ].x * sin;
36531 vertex.y = points[ j ].y;
36532 vertex.z = points[ j ].x * cos;
36533
36534 vertices.push( vertex.x, vertex.y, vertex.z );
36535
36536 // uv
36537
36538 uv.x = i / segments;
36539 uv.y = j / ( points.length - 1 );
36540
36541 uvs.push( uv.x, uv.y );
36542
36543 // normal
36544
36545 const x = initNormals[ 3 * j + 0 ] * sin;
36546 const y = initNormals[ 3 * j + 1 ];
36547 const z = initNormals[ 3 * j + 0 ] * cos;
36548
36549 normals.push( x, y, z );
36550
36551 }
36552
36553 }
36554
36555 // indices
36556
36557 for ( let i = 0; i < segments; i ++ ) {
36558
36559 for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
36560
36561 const base = j + i * points.length;
36562
36563 const a = base;
36564 const b = base + points.length;
36565 const c = base + points.length + 1;
36566 const d = base + 1;
36567
36568 // faces
36569
36570 indices.push( a, b, d );
36571 indices.push( c, d, b );
36572
36573 }
36574
36575 }
36576
36577 // build geometry
36578
36579 this.setIndex( indices );
36580 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36581 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36582 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36583
36584 }
36585
36586 copy( source ) {
36587
36588 super.copy( source );
36589
36590 this.parameters = Object.assign( {}, source.parameters );
36591
36592 return this;
36593
36594 }
36595
36596 static fromJSON( data ) {
36597
36598 return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength );
36599
36600 }
36601
36602 }
36603
36604 class CapsuleGeometry extends LatheGeometry {
36605
36606 constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) {
36607
36608 const path = new Path();
36609 path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );
36610 path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );
36611
36612 super( path.getPoints( capSegments ), radialSegments );
36613
36614 this.type = 'CapsuleGeometry';
36615
36616 this.parameters = {
36617 radius: radius,
36618 length: length,
36621 };
36622
36623 }
36624
36625 static fromJSON( data ) {
36626
36627 return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments );
36628
36629 }
36630
36631 }
36632
36633 class CircleGeometry extends BufferGeometry {
36634
36635 constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36636
36637 super();
36638
36639 this.type = 'CircleGeometry';
36640
36641 this.parameters = {
36642 radius: radius,
36646 };
36647
36648 segments = Math.max( 3, segments );
36649
36650 // buffers
36651
36652 const indices = [];
36653 const vertices = [];
36654 const normals = [];
36655 const uvs = [];
36656
36657 // helper variables
36658
36659 const vertex = new Vector3();
36660 const uv = new Vector2();
36661
36662 // center point
36663
36664 vertices.push( 0, 0, 0 );
36665 normals.push( 0, 0, 1 );
36666 uvs.push( 0.5, 0.5 );
36667
36668 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
36669
36670 const segment = thetaStart + s / segments * thetaLength;
36671
36672 // vertex
36673
36674 vertex.x = radius * Math.cos( segment );
36675 vertex.y = radius * Math.sin( segment );
36676
36677 vertices.push( vertex.x, vertex.y, vertex.z );
36678
36679 // normal
36680
36681 normals.push( 0, 0, 1 );
36682
36683 // uvs
36684
36685 uv.x = ( vertices[ i ] / radius + 1 ) / 2;
36686 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
36687
36688 uvs.push( uv.x, uv.y );
36689
36690 }
36691
36692 // indices
36693
36694 for ( let i = 1; i <= segments; i ++ ) {
36695
36696 indices.push( i, i + 1, 0 );
36697
36698 }
36699
36700 // build geometry
36701
36702 this.setIndex( indices );
36703 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36704 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36705 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36706
36707 }
36708
36709 copy( source ) {
36710
36711 super.copy( source );
36712
36713 this.parameters = Object.assign( {}, source.parameters );
36714
36715 return this;
36716
36717 }
36718
36719 static fromJSON( data ) {
36720
36721 return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );
36722
36723 }
36724
36725 }
36726
36727 class CylinderGeometry extends BufferGeometry {
36728
36729 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
36730
36731 super();
36732
36733 this.type = 'CylinderGeometry';
36734
36735 this.parameters = {
36738 height: height,
36744 };
36745
36746 const scope = this;
36747
36750
36751 // buffers
36752
36753 const indices = [];
36754 const vertices = [];
36755 const normals = [];
36756 const uvs = [];
36757
36758 // helper variables
36759
36760 let index = 0;
36761 const indexArray = [];
36762 const halfHeight = height / 2;
36763 let groupStart = 0;
36764
36765 // generate geometry
36766
36767 generateTorso();
36768
36769 if ( openEnded === false ) {
36770
36771 if ( radiusTop > 0 ) generateCap( true );
36772 if ( radiusBottom > 0 ) generateCap( false );
36773
36774 }
36775
36776 // build geometry
36777
36778 this.setIndex( indices );
36779 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
36780 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
36781 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
36782
36783 function generateTorso() {
36784
36785 const normal = new Vector3();
36786 const vertex = new Vector3();
36787
36788 let groupCount = 0;
36789
36790 // this will be used to calculate the normal
36791 const slope = ( radiusBottom - radiusTop ) / height;
36792
36793 // generate vertices, normals and uvs
36794
36795 for ( let y = 0; y <= heightSegments; y ++ ) {
36796
36797 const indexRow = [];
36798
36799 const v = y / heightSegments;
36800
36801 // calculate the radius of the current row
36802
36803 const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
36804
36805 for ( let x = 0; x <= radialSegments; x ++ ) {
36806
36807 const u = x / radialSegments;
36808
36809 const theta = u * thetaLength + thetaStart;
36810
36811 const sinTheta = Math.sin( theta );
36812 const cosTheta = Math.cos( theta );
36813
36814 // vertex
36815
36816 vertex.x = radius * sinTheta;
36817 vertex.y = - v * height + halfHeight;
36818 vertex.z = radius * cosTheta;
36819 vertices.push( vertex.x, vertex.y, vertex.z );
36820
36821 // normal
36822
36823 normal.set( sinTheta, slope, cosTheta ).normalize();
36824 normals.push( normal.x, normal.y, normal.z );
36825
36826 // uv
36827
36828 uvs.push( u, 1 - v );
36829
36830 // save index of vertex in respective row
36831
36832 indexRow.push( index ++ );
36833
36834 }
36835
36836 // now save vertices of the row in our index array
36837
36838 indexArray.push( indexRow );
36839
36840 }
36841
36842 // generate indices
36843
36844 for ( let x = 0; x < radialSegments; x ++ ) {
36845
36846 for ( let y = 0; y < heightSegments; y ++ ) {
36847
36848 // we use the index array to access the correct indices
36849
36850 const a = indexArray[ y ][ x ];
36851 const b = indexArray[ y + 1 ][ x ];
36852 const c = indexArray[ y + 1 ][ x + 1 ];
36853 const d = indexArray[ y ][ x + 1 ];
36854
36855 // faces
36856
36857 indices.push( a, b, d );
36858 indices.push( b, c, d );
36859
36860 // update group counter
36861
36862 groupCount += 6;
36863
36864 }
36865
36866 }
36867
36868 // add a group to the geometry. this will ensure multi material support
36869
36870 scope.addGroup( groupStart, groupCount, 0 );
36871
36872 // calculate new start value for groups
36873
36875
36876 }
36877
36878 function generateCap( top ) {
36879
36880 // save the index of the first center vertex
36881 const centerIndexStart = index;
36882
36883 const uv = new Vector2();
36884 const vertex = new Vector3();
36885
36886 let groupCount = 0;
36887
36888 const radius = ( top === true ) ? radiusTop : radiusBottom;
36889 const sign = ( top === true ) ? 1 : - 1;
36890
36891 // first we generate the center vertex data of the cap.
36892 // because the geometry needs one set of uvs per face,
36893 // we must generate a center vertex per face/segment
36894
36895 for ( let x = 1; x <= radialSegments; x ++ ) {
36896
36897 // vertex
36898
36899 vertices.push( 0, halfHeight * sign, 0 );
36900
36901 // normal
36902
36903 normals.push( 0, sign, 0 );
36904
36905 // uv
36906
36907 uvs.push( 0.5, 0.5 );
36908
36909 // increase index
36910
36911 index ++;
36912
36913 }
36914
36915 // save the index of the last center vertex
36916 const centerIndexEnd = index;
36917
36918 // now we generate the surrounding vertices, normals and uvs
36919
36920 for ( let x = 0; x <= radialSegments; x ++ ) {
36921
36922 const u = x / radialSegments;
36923 const theta = u * thetaLength + thetaStart;
36924
36925 const cosTheta = Math.cos( theta );
36926 const sinTheta = Math.sin( theta );
36927
36928 // vertex
36929
36930 vertex.x = radius * sinTheta;
36931 vertex.y = halfHeight * sign;
36932 vertex.z = radius * cosTheta;
36933 vertices.push( vertex.x, vertex.y, vertex.z );
36934
36935 // normal
36936
36937 normals.push( 0, sign, 0 );
36938
36939 // uv
36940
36941 uv.x = ( cosTheta * 0.5 ) + 0.5;
36942 uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
36943 uvs.push( uv.x, uv.y );
36944
36945 // increase index
36946
36947 index ++;
36948
36949 }
36950
36951 // generate indices
36952
36953 for ( let x = 0; x < radialSegments; x ++ ) {
36954
36955 const c = centerIndexStart + x;
36956 const i = centerIndexEnd + x;
36957
36958 if ( top === true ) {
36959
36960 // face top
36961
36962 indices.push( i, i + 1, c );
36963
36964 } else {
36965
36966 // face bottom
36967
36968 indices.push( i + 1, i, c );
36969
36970 }
36971
36972 groupCount += 3;
36973
36974 }
36975
36976 // add a group to the geometry. this will ensure multi material support
36977
36978 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
36979
36980 // calculate new start value for groups
36981
36983
36984 }
36985
36986 }
36987
36988 copy( source ) {
36989
36990 super.copy( source );
36991
36992 this.parameters = Object.assign( {}, source.parameters );
36993
36994 return this;
36995
36996 }
36997
36998 static fromJSON( data ) {
36999
37000 return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
37001
37002 }
37003
37004 }
37005
37006 class ConeGeometry extends CylinderGeometry {
37007
37008 constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {
37009
37011
37012 this.type = 'ConeGeometry';
37013
37014 this.parameters = {
37015 radius: radius,
37016 height: height,
37022 };
37023
37024 }
37025
37026 static fromJSON( data ) {
37027
37028 return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );
37029
37030 }
37031
37032 }
37033
37034 class PolyhedronGeometry extends BufferGeometry {
37035
37036 constructor( vertices = [], indices = [], radius = 1, detail = 0 ) {
37037
37038 super();
37039
37040 this.type = 'PolyhedronGeometry';
37041
37042 this.parameters = {
37045 radius: radius,
37046 detail: detail
37047 };
37048
37049 // default buffer data
37050
37051 const vertexBuffer = [];
37052 const uvBuffer = [];
37053
37054 // the subdivision creates the vertex buffer data
37055
37056 subdivide( detail );
37057
37058 // all vertices should lie on a conceptual sphere with a given radius
37059
37061
37062 // finally, create the uv data
37063
37064 generateUVs();
37065
37066 // build non-indexed geometry
37067
37068 this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
37069 this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
37070 this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
37071
37072 if ( detail === 0 ) {
37073
37074 this.computeVertexNormals(); // flat normals
37075
37076 } else {
37077
37078 this.normalizeNormals(); // smooth normals
37079
37080 }
37081
37082 // helper functions
37083
37084 function subdivide( detail ) {
37085
37086 const a = new Vector3();
37087 const b = new Vector3();
37088 const c = new Vector3();
37089
37090 // iterate over all faces and apply a subdivision with the given detail value
37091
37092 for ( let i = 0; i < indices.length; i += 3 ) {
37093
37094 // get the vertices of the face
37095
37096 getVertexByIndex( indices[ i + 0 ], a );
37097 getVertexByIndex( indices[ i + 1 ], b );
37098 getVertexByIndex( indices[ i + 2 ], c );
37099
37100 // perform subdivision
37101
37102 subdivideFace( a, b, c, detail );
37103
37104 }
37105
37106 }
37107
37108 function subdivideFace( a, b, c, detail ) {
37109
37110 const cols = detail + 1;
37111
37112 // we use this multidimensional array as a data structure for creating the subdivision
37113
37114 const v = [];
37115
37116 // construct all of the vertices for this subdivision
37117
37118 for ( let i = 0; i <= cols; i ++ ) {
37119
37120 v[ i ] = [];
37121
37122 const aj = a.clone().lerp( c, i / cols );
37123 const bj = b.clone().lerp( c, i / cols );
37124
37125 const rows = cols - i;
37126
37127 for ( let j = 0; j <= rows; j ++ ) {
37128
37129 if ( j === 0 && i === cols ) {
37130
37131 v[ i ][ j ] = aj;
37132
37133 } else {
37134
37135 v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
37136
37137 }
37138
37139 }
37140
37141 }
37142
37143 // construct all of the faces
37144
37145 for ( let i = 0; i < cols; i ++ ) {
37146
37147 for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
37148
37149 const k = Math.floor( j / 2 );
37150
37151 if ( j % 2 === 0 ) {
37152
37153 pushVertex( v[ i ][ k + 1 ] );
37154 pushVertex( v[ i + 1 ][ k ] );
37155 pushVertex( v[ i ][ k ] );
37156
37157 } else {
37158
37159 pushVertex( v[ i ][ k + 1 ] );
37160 pushVertex( v[ i + 1 ][ k + 1 ] );
37161 pushVertex( v[ i + 1 ][ k ] );
37162
37163 }
37164
37165 }
37166
37167 }
37168
37169 }
37170
37171 function applyRadius( radius ) {
37172
37173 const vertex = new Vector3();
37174
37175 // iterate over the entire buffer and apply the radius to each vertex
37176
37177 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37178
37179 vertex.x = vertexBuffer[ i + 0 ];
37180 vertex.y = vertexBuffer[ i + 1 ];
37181 vertex.z = vertexBuffer[ i + 2 ];
37182
37183 vertex.normalize().multiplyScalar( radius );
37184
37185 vertexBuffer[ i + 0 ] = vertex.x;
37186 vertexBuffer[ i + 1 ] = vertex.y;
37187 vertexBuffer[ i + 2 ] = vertex.z;
37188
37189 }
37190
37191 }
37192
37193 function generateUVs() {
37194
37195 const vertex = new Vector3();
37196
37197 for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
37198
37199 vertex.x = vertexBuffer[ i + 0 ];
37200 vertex.y = vertexBuffer[ i + 1 ];
37201 vertex.z = vertexBuffer[ i + 2 ];
37202
37203 const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
37204 const v = inclination( vertex ) / Math.PI + 0.5;
37205 uvBuffer.push( u, 1 - v );
37206
37207 }
37208
37209 correctUVs();
37210
37211 correctSeam();
37212
37213 }
37214
37215 function correctSeam() {
37216
37217 // handle case when face straddles the seam, see #3269
37218
37219 for ( let i = 0; i < uvBuffer.length; i += 6 ) {
37220
37221 // uv data of a single face
37222
37223 const x0 = uvBuffer[ i + 0 ];
37224 const x1 = uvBuffer[ i + 2 ];
37225 const x2 = uvBuffer[ i + 4 ];
37226
37227 const max = Math.max( x0, x1, x2 );
37228 const min = Math.min( x0, x1, x2 );
37229
37230 // 0.9 is somewhat arbitrary
37231
37232 if ( max > 0.9 && min < 0.1 ) {
37233
37234 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
37235 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
37236 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
37237
37238 }
37239
37240 }
37241
37242 }
37243
37244 function pushVertex( vertex ) {
37245
37246 vertexBuffer.push( vertex.x, vertex.y, vertex.z );
37247
37248 }
37249
37250 function getVertexByIndex( index, vertex ) {
37251
37252 const stride = index * 3;
37253
37254 vertex.x = vertices[ stride + 0 ];
37255 vertex.y = vertices[ stride + 1 ];
37256 vertex.z = vertices[ stride + 2 ];
37257
37258 }
37259
37260 function correctUVs() {
37261
37262 const a = new Vector3();
37263 const b = new Vector3();
37264 const c = new Vector3();
37265
37266 const centroid = new Vector3();
37267
37268 const uvA = new Vector2();
37269 const uvB = new Vector2();
37270 const uvC = new Vector2();
37271
37272 for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
37273
37274 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
37275 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
37276 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
37277
37278 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
37279 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
37280 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
37281
37282 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
37283
37284 const azi = azimuth( centroid );
37285
37286 correctUV( uvA, j + 0, a, azi );
37287 correctUV( uvB, j + 2, b, azi );
37288 correctUV( uvC, j + 4, c, azi );
37289
37290 }
37291
37292 }
37293
37294 function correctUV( uv, stride, vector, azimuth ) {
37295
37296 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
37297
37298 uvBuffer[ stride ] = uv.x - 1;
37299
37300 }
37301
37302 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
37303
37304 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
37305
37306 }
37307
37308 }
37309
37310 // Angle around the Y axis, counter-clockwise when looking from above.
37311
37312 function azimuth( vector ) {
37313
37314 return Math.atan2( vector.z, - vector.x );
37315
37316 }
37317
37318
37319 // Angle above the XZ plane.
37320
37321 function inclination( vector ) {
37322
37323 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
37324
37325 }
37326
37327 }
37328
37329 copy( source ) {
37330
37331 super.copy( source );
37332
37333 this.parameters = Object.assign( {}, source.parameters );
37334
37335 return this;
37336
37337 }
37338
37339 static fromJSON( data ) {
37340
37341 return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details );
37342
37343 }
37344
37345 }
37346
37348
37349 constructor( radius = 1, detail = 0 ) {
37350
37351 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
37352 const r = 1 / t;
37353
37354 const vertices = [
37355
37356 // (±1, ±1, ±1)
37357 - 1, - 1, - 1, - 1, - 1, 1,
37358 - 1, 1, - 1, - 1, 1, 1,
37359 1, - 1, - 1, 1, - 1, 1,
37360 1, 1, - 1, 1, 1, 1,
37361
37362 // (0, ±1/φ, ±φ)
37363 0, - r, - t, 0, - r, t,
37364 0, r, - t, 0, r, t,
37365
37366 // (±1/φ, ±φ, 0)
37367 - r, - t, 0, - r, t, 0,
37368 r, - t, 0, r, t, 0,
37369
37370 // (±φ, 0, ±1/φ)
37371 - t, 0, - r, t, 0, - r,
37372 - t, 0, r, t, 0, r
37373 ];
37374
37375 const indices = [
37376 3, 11, 7, 3, 7, 15, 3, 15, 13,
37377 7, 19, 17, 7, 17, 6, 7, 6, 15,
37378 17, 4, 8, 17, 8, 10, 17, 10, 6,
37379 8, 0, 16, 8, 16, 2, 8, 2, 10,
37380 0, 12, 1, 0, 1, 18, 0, 18, 16,
37381 6, 10, 2, 6, 2, 13, 6, 13, 15,
37382 2, 16, 18, 2, 18, 3, 2, 3, 13,
37383 18, 1, 9, 18, 9, 11, 18, 11, 3,
37384 4, 14, 12, 4, 12, 0, 4, 0, 8,
37385 11, 9, 5, 11, 5, 19, 11, 19, 7,
37386 19, 5, 14, 19, 14, 4, 19, 4, 17,
37387 1, 12, 14, 1, 14, 5, 1, 5, 9
37388 ];
37389
37391
37392 this.type = 'DodecahedronGeometry';
37393
37394 this.parameters = {
37395 radius: radius,
37396 detail: detail
37397 };
37398
37399 }
37400
37401 static fromJSON( data ) {
37402
37403 return new DodecahedronGeometry( data.radius, data.detail );
37404
37405 }
37406
37407 }
37408
37409 const _v0 = /*@__PURE__*/ new Vector3();
37410 const _v1$1 = /*@__PURE__*/ new Vector3();
37411 const _normal = /*@__PURE__*/ new Vector3();
37412 const _triangle = /*@__PURE__*/ new Triangle();
37413
37414 class EdgesGeometry extends BufferGeometry {
37415
37416 constructor( geometry = null, thresholdAngle = 1 ) {
37417
37418 super();
37419
37420 this.type = 'EdgesGeometry';
37421
37422 this.parameters = {
37425 };
37426
37427 if ( geometry !== null ) {
37428
37429 const precisionPoints = 4;
37430 const precision = Math.pow( 10, precisionPoints );
37431 const thresholdDot = Math.cos( DEG2RAD * thresholdAngle );
37432
37433 const indexAttr = geometry.getIndex();
37434 const positionAttr = geometry.getAttribute( 'position' );
37435 const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
37436
37437 const indexArr = [ 0, 0, 0 ];
37438 const vertKeys = [ 'a', 'b', 'c' ];
37439 const hashes = new Array( 3 );
37440
37441 const edgeData = {};
37442 const vertices = [];
37443 for ( let i = 0; i < indexCount; i += 3 ) {
37444
37445 if ( indexAttr ) {
37446
37447 indexArr[ 0 ] = indexAttr.getX( i );
37448 indexArr[ 1 ] = indexAttr.getX( i + 1 );
37449 indexArr[ 2 ] = indexAttr.getX( i + 2 );
37450
37451 } else {
37452
37453 indexArr[ 0 ] = i;
37454 indexArr[ 1 ] = i + 1;
37455 indexArr[ 2 ] = i + 2;
37456
37457 }
37458
37459 const { a, b, c } = _triangle;
37460 a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
37461 b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
37462 c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
37463 _triangle.getNormal( _normal );
37464
37465 // create hashes for the edge from the vertices
37466 hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;
37467 hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;
37468 hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;
37469
37470 // skip degenerate triangles
37471 if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {
37472
37473 continue;
37474
37475 }
37476
37477 // iterate over every edge
37478 for ( let j = 0; j < 3; j ++ ) {
37479
37480 // get the first and next vertex making up the edge
37481 const jNext = ( j + 1 ) % 3;
37482 const vecHash0 = hashes[ j ];
37483 const vecHash1 = hashes[ jNext ];
37484 const v0 = _triangle[ vertKeys[ j ] ];
37485 const v1 = _triangle[ vertKeys[ jNext ] ];
37486
37487 const hash = `${ vecHash0 }_${ vecHash1 }`;
37488 const reverseHash = `${ vecHash1 }_${ vecHash0 }`;
37489
37491
37492 // if we found a sibling edge add it into the vertex array if
37493 // it meets the angle threshold and delete the edge from the map.
37494 if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {
37495
37496 vertices.push( v0.x, v0.y, v0.z );
37497 vertices.push( v1.x, v1.y, v1.z );
37498
37499 }
37500
37501 edgeData[ reverseHash ] = null;
37502
37503 } else if ( ! ( hash in edgeData ) ) {
37504
37505 // if we've already got an edge here then skip adding a new one
37506 edgeData[ hash ] = {
37507
37508 index0: indexArr[ j ],
37509 index1: indexArr[ jNext ],
37510 normal: _normal.clone(),
37511
37512 };
37513
37514 }
37515
37516 }
37517
37518 }
37519
37520 // iterate over all remaining, unmatched edges and add them to the vertex array
37521 for ( const key in edgeData ) {
37522
37523 if ( edgeData[ key ] ) {
37524
37525 const { index0, index1 } = edgeData[ key ];
37526 _v0.fromBufferAttribute( positionAttr, index0 );
37527 _v1$1.fromBufferAttribute( positionAttr, index1 );
37528
37529 vertices.push( _v0.x, _v0.y, _v0.z );
37530 vertices.push( _v1$1.x, _v1$1.y, _v1$1.z );
37531
37532 }
37533
37534 }
37535
37536 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
37537
37538 }
37539
37540 }
37541
37542 copy( source ) {
37543
37544 super.copy( source );
37545
37546 this.parameters = Object.assign( {}, source.parameters );
37547
37548 return this;
37549
37550 }
37551
37552 }
37553
37554 class Shape extends Path {
37555
37556 constructor( points ) {
37557
37558 super( points );
37559
37560 this.uuid = generateUUID();
37561
37562 this.type = 'Shape';
37563
37564 this.holes = [];
37565
37566 }
37567
37569
37570 const holesPts = [];
37571
37572 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37573
37574 holesPts[ i ] = this.holes[ i ].getPoints( divisions );
37575
37576 }
37577
37578 return holesPts;
37579
37580 }
37581
37582 // get points of shape and holes (keypoints based on segments parameter)
37583
37585
37586 return {
37587
37588 shape: this.getPoints( divisions ),
37590
37591 };
37592
37593 }
37594
37595 copy( source ) {
37596
37597 super.copy( source );
37598
37599 this.holes = [];
37600
37601 for ( let i = 0, l = source.holes.length; i < l; i ++ ) {
37602
37603 const hole = source.holes[ i ];
37604
37605 this.holes.push( hole.clone() );
37606
37607 }
37608
37609 return this;
37610
37611 }
37612
37613 toJSON() {
37614
37615 const data = super.toJSON();
37616
37617 data.uuid = this.uuid;
37618 data.holes = [];
37619
37620 for ( let i = 0, l = this.holes.length; i < l; i ++ ) {
37621
37622 const hole = this.holes[ i ];
37623 data.holes.push( hole.toJSON() );
37624
37625 }
37626
37627 return data;
37628
37629 }
37630
37631 fromJSON( json ) {
37632
37633 super.fromJSON( json );
37634
37635 this.uuid = json.uuid;
37636 this.holes = [];
37637
37638 for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
37639
37640 const hole = json.holes[ i ];
37641 this.holes.push( new Path().fromJSON( hole ) );
37642
37643 }
37644
37645 return this;
37646
37647 }
37648
37649 }
37650
37655 const Earcut = {
37656
37657 triangulate: function ( data, holeIndices, dim = 2 ) {
37658
37659 const hasHoles = holeIndices && holeIndices.length;
37660 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
37661 let outerNode = linkedList( data, 0, outerLen, dim, true );
37662 const triangles = [];
37663
37664 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
37665
37666 let minX, minY, maxX, maxY, x, y, invSize;
37667
37669
37670 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
37671 if ( data.length > 80 * dim ) {
37672
37673 minX = maxX = data[ 0 ];
37674 minY = maxY = data[ 1 ];
37675
37676 for ( let i = dim; i < outerLen; i += dim ) {
37677
37678 x = data[ i ];
37679 y = data[ i + 1 ];
37680 if ( x < minX ) minX = x;
37681 if ( y < minY ) minY = y;
37682 if ( x > maxX ) maxX = x;
37683 if ( y > maxY ) maxY = y;
37684
37685 }
37686
37687 // minX, minY and invSize are later used to transform coords into integers for z-order calculation
37688 invSize = Math.max( maxX - minX, maxY - minY );
37689 invSize = invSize !== 0 ? 32767 / invSize : 0;
37690
37691 }
37692
37694
37695 return triangles;
37696
37697 }
37698
37699 };
37700
37701 // create a circular doubly linked list from polygon points in the specified winding order
37702 function linkedList( data, start, end, dim, clockwise ) {
37703
37704 let i, last;
37705
37706 if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {
37707
37708 for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37709
37710 } else {
37711
37712 for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );
37713
37714 }
37715
37716 if ( last && equals( last, last.next ) ) {
37717
37718 removeNode( last );
37719 last = last.next;
37720
37721 }
37722
37723 return last;
37724
37725 }
37726
37727 // eliminate colinear or duplicate points
37728 function filterPoints( start, end ) {
37729
37730 if ( ! start ) return start;
37731 if ( ! end ) end = start;
37732
37733 let p = start,
37734 again;
37735 do {
37736
37737 again = false;
37738
37739 if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {
37740
37741 removeNode( p );
37742 p = end = p.prev;
37743 if ( p === p.next ) break;
37744 again = true;
37745
37746 } else {
37747
37748 p = p.next;
37749
37750 }
37751
37752 } while ( again || p !== end );
37753
37754 return end;
37755
37756 }
37757
37758 // main ear slicing loop which triangulates a polygon (given as a linked list)
37759 function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
37760
37761 if ( ! ear ) return;
37762
37763 // interlink polygon nodes in z-order
37764 if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );
37765
37766 let stop = ear,
37767 prev, next;
37768
37769 // iterate through ears, slicing them one by one
37770 while ( ear.prev !== ear.next ) {
37771
37772 prev = ear.prev;
37773 next = ear.next;
37774
37775 if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {
37776
37777 // cut off the triangle
37778 triangles.push( prev.i / dim | 0 );
37779 triangles.push( ear.i / dim | 0 );
37780 triangles.push( next.i / dim | 0 );
37781
37782 removeNode( ear );
37783
37784 // skipping the next vertex leads to less sliver triangles
37785 ear = next.next;
37786 stop = next.next;
37787
37788 continue;
37789
37790 }
37791
37792 ear = next;
37793
37794 // if we looped through the whole remaining polygon and can't find any more ears
37795 if ( ear === stop ) {
37796
37797 // try filtering points and slicing again
37798 if ( ! pass ) {
37799
37801
37802 // if this didn't work, try curing all small self-intersections locally
37803
37804 } else if ( pass === 1 ) {
37805
37808
37809 // as a last resort, try splitting the remaining polygon into two
37810
37811 } else if ( pass === 2 ) {
37812
37814
37815 }
37816
37817 break;
37818
37819 }
37820
37821 }
37822
37823 }
37824
37825 // check whether a polygon node forms a valid ear with adjacent nodes
37826 function isEar( ear ) {
37827
37828 const a = ear.prev,
37829 b = ear,
37830 c = ear.next;
37831
37832 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37833
37834 // now make sure we don't have other points inside the potential ear
37835 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37836
37837 // triangle bbox; min & max are calculated like this for speed
37838 const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37839 y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37840 x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37841 y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37842
37843 let p = c.next;
37844 while ( p !== a ) {
37845
37846 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
37847 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
37848 area( p.prev, p, p.next ) >= 0 ) return false;
37849 p = p.next;
37850
37851 }
37852
37853 return true;
37854
37855 }
37856
37857 function isEarHashed( ear, minX, minY, invSize ) {
37858
37859 const a = ear.prev,
37860 b = ear,
37861 c = ear.next;
37862
37863 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
37864
37865 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
37866
37867 // triangle bbox; min & max are calculated like this for speed
37868 const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
37869 y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
37870 x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
37871 y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
37872
37873 // z-order range for the current triangle bbox;
37874 const minZ = zOrder( x0, y0, minX, minY, invSize ),
37875 maxZ = zOrder( x1, y1, minX, minY, invSize );
37876
37877 let p = ear.prevZ,
37878 n = ear.nextZ;
37879
37880 // look for points inside the triangle in both directions
37881 while ( p && p.z >= minZ && n && n.z <= maxZ ) {
37882
37883 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37884 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37885 p = p.prevZ;
37886
37887 if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37888 pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37889 n = n.nextZ;
37890
37891 }
37892
37893 // look for remaining points in decreasing z-order
37894 while ( p && p.z >= minZ ) {
37895
37896 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
37897 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;
37898 p = p.prevZ;
37899
37900 }
37901
37902 // look for remaining points in increasing z-order
37903 while ( n && n.z <= maxZ ) {
37904
37905 if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
37906 pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;
37907 n = n.nextZ;
37908
37909 }
37910
37911 return true;
37912
37913 }
37914
37915 // go through all polygon nodes and cure small local self-intersections
37916 function cureLocalIntersections( start, triangles, dim ) {
37917
37918 let p = start;
37919 do {
37920
37921 const a = p.prev,
37922 b = p.next.next;
37923
37924 if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
37925
37926 triangles.push( a.i / dim | 0 );
37927 triangles.push( p.i / dim | 0 );
37928 triangles.push( b.i / dim | 0 );
37929
37930 // remove two nodes involved
37931 removeNode( p );
37932 removeNode( p.next );
37933
37934 p = start = b;
37935
37936 }
37937
37938 p = p.next;
37939
37940 } while ( p !== start );
37941
37942 return filterPoints( p );
37943
37944 }
37945
37946 // try splitting polygon into two and triangulate them independently
37947 function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
37948
37949 // look for a valid diagonal that divides the polygon into two
37950 let a = start;
37951 do {
37952
37953 let b = a.next.next;
37954 while ( b !== a.prev ) {
37955
37956 if ( a.i !== b.i && isValidDiagonal( a, b ) ) {
37957
37958 // split the polygon in two by the diagonal
37959 let c = splitPolygon( a, b );
37960
37961 // filter colinear points around the cuts
37962 a = filterPoints( a, a.next );
37963 c = filterPoints( c, c.next );
37964
37965 // run earcut on each half
37968 return;
37969
37970 }
37971
37972 b = b.next;
37973
37974 }
37975
37976 a = a.next;
37977
37978 } while ( a !== start );
37979
37980 }
37981
37982 // link every hole into the outer loop, producing a single-ring polygon without holes
37984
37985 const queue = [];
37986 let i, len, start, end, list;
37987
37988 for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
37989
37990 start = holeIndices[ i ] * dim;
37991 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;
37992 list = linkedList( data, start, end, dim, false );
37993 if ( list === list.next ) list.steiner = true;
37994 queue.push( getLeftmost( list ) );
37995
37996 }
37997
37998 queue.sort( compareX );
37999
38000 // process holes from left to right
38001 for ( i = 0; i < queue.length; i ++ ) {
38002
38004
38005 }
38006
38007 return outerNode;
38008
38009 }
38010
38011 function compareX( a, b ) {
38012
38013 return a.x - b.x;
38014
38015 }
38016
38017 // find a bridge between vertices that connects hole with an outer ring and link it
38018 function eliminateHole( hole, outerNode ) {
38019
38020 const bridge = findHoleBridge( hole, outerNode );
38021 if ( ! bridge ) {
38022
38023 return outerNode;
38024
38025 }
38026
38028
38029 // filter collinear points around the cuts
38031 return filterPoints( bridge, bridge.next );
38032
38033 }
38034
38035 // David Eberly's algorithm for finding a bridge between hole and outer polygon
38036 function findHoleBridge( hole, outerNode ) {
38037
38038 let p = outerNode,
38039 qx = - Infinity,
38040 m;
38041
38042 const hx = hole.x, hy = hole.y;
38043
38044 // find a segment intersected by a ray from the hole's leftmost point to the left;
38045 // segment's endpoint with lesser x will be potential connection point
38046 do {
38047
38048 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
38049
38050 const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
38051 if ( x <= hx && x > qx ) {
38052
38053 qx = x;
38054 m = p.x < p.next.x ? p : p.next;
38055 if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint
38056
38057 }
38058
38059 }
38060
38061 p = p.next;
38062
38063 } while ( p !== outerNode );
38064
38065 if ( ! m ) return null;
38066
38067 // look for points inside the triangle of hole point, segment intersection and endpoint;
38068 // if there are no points found, we have a valid connection;
38069 // otherwise choose the point of the minimum angle with the ray as connection point
38070
38071 const stop = m,
38072 mx = m.x,
38073 my = m.y;
38075
38076 p = m;
38077
38078 do {
38079
38080 if ( hx >= p.x && p.x >= mx && hx !== p.x &&
38081 pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
38082
38083 tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
38084
38085 if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
38086
38087 m = p;
38088 tanMin = tan;
38089
38090 }
38091
38092 }
38093
38094 p = p.next;
38095
38096 } while ( p !== stop );
38097
38098 return m;
38099
38100 }
38101
38102 // whether sector in vertex m contains sector in vertex p in the same coordinates
38103 function sectorContainsSector( m, p ) {
38104
38105 return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
38106
38107 }
38108
38109 // interlink polygon nodes in z-order
38110 function indexCurve( start, minX, minY, invSize ) {
38111
38112 let p = start;
38113 do {
38114
38115 if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );
38116 p.prevZ = p.prev;
38117 p.nextZ = p.next;
38118 p = p.next;
38119
38120 } while ( p !== start );
38121
38122 p.prevZ.nextZ = null;
38123 p.prevZ = null;
38124
38125 sortLinked( p );
38126
38127 }
38128
38129 // Simon Tatham's linked list merge sort algorithm
38130 // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
38131 function sortLinked( list ) {
38132
38133 let i, p, q, e, tail, numMerges, pSize, qSize,
38134 inSize = 1;
38135
38136 do {
38137
38138 p = list;
38139 list = null;
38140 tail = null;
38141 numMerges = 0;
38142
38143 while ( p ) {
38144
38145 numMerges ++;
38146 q = p;
38147 pSize = 0;
38148 for ( i = 0; i < inSize; i ++ ) {
38149
38150 pSize ++;
38151 q = q.nextZ;
38152 if ( ! q ) break;
38153
38154 }
38155
38156 qSize = inSize;
38157
38158 while ( pSize > 0 || ( qSize > 0 && q ) ) {
38159
38160 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {
38161
38162 e = p;
38163 p = p.nextZ;
38164 pSize --;
38165
38166 } else {
38167
38168 e = q;
38169 q = q.nextZ;
38170 qSize --;
38171
38172 }
38173
38174 if ( tail ) tail.nextZ = e;
38175 else list = e;
38176
38177 e.prevZ = tail;
38178 tail = e;
38179
38180 }
38181
38182 p = q;
38183
38184 }
38185
38186 tail.nextZ = null;
38187 inSize *= 2;
38188
38189 } while ( numMerges > 1 );
38190
38191 return list;
38192
38193 }
38194
38195 // z-order of a point given coords and inverse of the longer side of data bbox
38196 function zOrder( x, y, minX, minY, invSize ) {
38197
38198 // coords are transformed into non-negative 15-bit integer range
38199 x = ( x - minX ) * invSize | 0;
38200 y = ( y - minY ) * invSize | 0;
38201
38202 x = ( x | ( x << 8 ) ) & 0x00FF00FF;
38203 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F;
38204 x = ( x | ( x << 2 ) ) & 0x33333333;
38205 x = ( x | ( x << 1 ) ) & 0x55555555;
38206
38207 y = ( y | ( y << 8 ) ) & 0x00FF00FF;
38208 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F;
38209 y = ( y | ( y << 2 ) ) & 0x33333333;
38210 y = ( y | ( y << 1 ) ) & 0x55555555;
38211
38212 return x | ( y << 1 );
38213
38214 }
38215
38216 // find the leftmost node of a polygon ring
38217 function getLeftmost( start ) {
38218
38219 let p = start,
38220 leftmost = start;
38221 do {
38222
38223 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;
38224 p = p.next;
38225
38226 } while ( p !== start );
38227
38228 return leftmost;
38229
38230 }
38231
38232 // check if a point lies within a convex triangle
38233 function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
38234
38235 return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&
38236 ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&
38237 ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );
38238
38239 }
38240
38241 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
38242 function isValidDiagonal( a, b ) {
38243
38244 return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
38245 ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
38246 ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
38247 equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
38248
38249 }
38250
38251 // signed area of a triangle
38252 function area( p, q, r ) {
38253
38254 return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );
38255
38256 }
38257
38258 // check if two points are equal
38259 function equals( p1, p2 ) {
38260
38261 return p1.x === p2.x && p1.y === p2.y;
38262
38263 }
38264
38265 // check if two segments intersect
38266 function intersects( p1, q1, p2, q2 ) {
38267
38268 const o1 = sign( area( p1, q1, p2 ) );
38269 const o2 = sign( area( p1, q1, q2 ) );
38270 const o3 = sign( area( p2, q2, p1 ) );
38271 const o4 = sign( area( p2, q2, q1 ) );
38272
38273 if ( o1 !== o2 && o3 !== o4 ) return true; // general case
38274
38275 if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
38276 if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
38277 if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
38278 if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
38279
38280 return false;
38281
38282 }
38283
38284 // for collinear points p, q, r, check if point q lies on segment pr
38285 function onSegment( p, q, r ) {
38286
38287 return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
38288
38289 }
38290
38291 function sign( num ) {
38292
38293 return num > 0 ? 1 : num < 0 ? - 1 : 0;
38294
38295 }
38296
38297 // check if a polygon diagonal intersects any polygon segments
38298 function intersectsPolygon( a, b ) {
38299
38300 let p = a;
38301 do {
38302
38303 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
38304 intersects( p, p.next, a, b ) ) return true;
38305 p = p.next;
38306
38307 } while ( p !== a );
38308
38309 return false;
38310
38311 }
38312
38313 // check if a polygon diagonal is locally inside the polygon
38314 function locallyInside( a, b ) {
38315
38316 return area( a.prev, a, a.next ) < 0 ?
38317 area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :
38318 area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;
38319
38320 }
38321
38322 // check if the middle point of a polygon diagonal is inside the polygon
38323 function middleInside( a, b ) {
38324
38325 let p = a,
38326 inside = false;
38327 const px = ( a.x + b.x ) / 2,
38328 py = ( a.y + b.y ) / 2;
38329 do {
38330
38331 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
38332 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )
38333 inside = ! inside;
38334 p = p.next;
38335
38336 } while ( p !== a );
38337
38338 return inside;
38339
38340 }
38341
38342 // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
38343 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
38344 function splitPolygon( a, b ) {
38345
38346 const a2 = new Node( a.i, a.x, a.y ),
38347 b2 = new Node( b.i, b.x, b.y ),
38348 an = a.next,
38349 bp = b.prev;
38350
38351 a.next = b;
38352 b.prev = a;
38353
38354 a2.next = an;
38355 an.prev = a2;
38356
38357 b2.next = a2;
38358 a2.prev = b2;
38359
38360 bp.next = b2;
38361 b2.prev = bp;
38362
38363 return b2;
38364
38365 }
38366
38367 // create a node and optionally link it with previous one (in a circular doubly linked list)
38368 function insertNode( i, x, y, last ) {
38369
38370 const p = new Node( i, x, y );
38371
38372 if ( ! last ) {
38373
38374 p.prev = p;
38375 p.next = p;
38376
38377 } else {
38378
38379 p.next = last.next;
38380 p.prev = last;
38381 last.next.prev = p;
38382 last.next = p;
38383
38384 }
38385
38386 return p;
38387
38388 }
38389
38390 function removeNode( p ) {
38391
38392 p.next.prev = p.prev;
38393 p.prev.next = p.next;
38394
38395 if ( p.prevZ ) p.prevZ.nextZ = p.nextZ;
38396 if ( p.nextZ ) p.nextZ.prevZ = p.prevZ;
38397
38398 }
38399
38400 function Node( i, x, y ) {
38401
38402 // vertex index in coordinates array
38403 this.i = i;
38404
38405 // vertex coordinates
38406 this.x = x;
38407 this.y = y;
38408
38409 // previous and next vertex nodes in a polygon ring
38410 this.prev = null;
38411 this.next = null;
38412
38413 // z-order curve value
38414 this.z = 0;
38415
38416 // previous and next nodes in z-order
38417 this.prevZ = null;
38418 this.nextZ = null;
38419
38420 // indicates whether this is a steiner point
38421 this.steiner = false;
38422
38423 }
38424
38425 function signedArea( data, start, end, dim ) {
38426
38427 let sum = 0;
38428 for ( let i = start, j = end - dim; i < end; i += dim ) {
38429
38430 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );
38431 j = i;
38432
38433 }
38434
38435 return sum;
38436
38437 }
38438
38439 class ShapeUtils {
38440
38441 // calculate area of the contour polygon
38442
38443 static area( contour ) {
38444
38445 const n = contour.length;
38446 let a = 0.0;
38447
38448 for ( let p = n - 1, q = 0; q < n; p = q ++ ) {
38449
38450 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
38451
38452 }
38453
38454 return a * 0.5;
38455
38456 }
38457
38458 static isClockWise( pts ) {
38459
38460 return ShapeUtils.area( pts ) < 0;
38461
38462 }
38463
38464 static triangulateShape( contour, holes ) {
38465
38466 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]
38467 const holeIndices = []; // array of hole indices
38468 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]
38469
38472
38473 //
38474
38475 let holeIndex = contour.length;
38476
38477 holes.forEach( removeDupEndPts );
38478
38479 for ( let i = 0; i < holes.length; i ++ ) {
38480
38481 holeIndices.push( holeIndex );
38482 holeIndex += holes[ i ].length;
38483 addContour( vertices, holes[ i ] );
38484
38485 }
38486
38487 //
38488
38489 const triangles = Earcut.triangulate( vertices, holeIndices );
38490
38491 //
38492
38493 for ( let i = 0; i < triangles.length; i += 3 ) {
38494
38495 faces.push( triangles.slice( i, i + 3 ) );
38496
38497 }
38498
38499 return faces;
38500
38501 }
38502
38503 }
38504
38505 function removeDupEndPts( points ) {
38506
38507 const l = points.length;
38508
38509 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {
38510
38511 points.pop();
38512
38513 }
38514
38515 }
38516
38517 function addContour( vertices, contour ) {
38518
38519 for ( let i = 0; i < contour.length; i ++ ) {
38520
38521 vertices.push( contour[ i ].x );
38522 vertices.push( contour[ i ].y );
38523
38524 }
38525
38526 }
38527
38551 class ExtrudeGeometry extends BufferGeometry {
38552
38553 constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) {
38554
38555 super();
38556
38557 this.type = 'ExtrudeGeometry';
38558
38559 this.parameters = {
38560 shapes: shapes,
38562 };
38563
38564 shapes = Array.isArray( shapes ) ? shapes : [ shapes ];
38565
38566 const scope = this;
38567
38568 const verticesArray = [];
38569 const uvArray = [];
38570
38571 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
38572
38573 const shape = shapes[ i ];
38574 addShape( shape );
38575
38576 }
38577
38578 // build geometry
38579
38580 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );
38581 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );
38582
38583 this.computeVertexNormals();
38584
38585 // functions
38586
38587 function addShape( shape ) {
38588
38589 const placeholder = [];
38590
38591 // options
38592
38593 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;
38594 const steps = options.steps !== undefined ? options.steps : 1;
38595 const depth = options.depth !== undefined ? options.depth : 1;
38596
38597 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;
38598 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;
38599 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;
38600 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;
38601 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;
38602
38603 const extrudePath = options.extrudePath;
38604
38605 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;
38606
38607 //
38608
38609 let extrudePts, extrudeByPath = false;
38611
38612 if ( extrudePath ) {
38613
38614 extrudePts = extrudePath.getSpacedPoints( steps );
38615
38616 extrudeByPath = true;
38617 bevelEnabled = false; // bevels not supported for path extrusion
38618
38619 // SETUP TNB variables
38620
38621 // TODO1 - have a .isClosed in spline?
38622
38623 splineTube = extrudePath.computeFrenetFrames( steps, false );
38624
38625 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
38626
38627 binormal = new Vector3();
38628 normal = new Vector3();
38629 position2 = new Vector3();
38630
38631 }
38632
38633 // Safeguards if bevels are not enabled
38634
38635 if ( ! bevelEnabled ) {
38636
38637 bevelSegments = 0;
38638 bevelThickness = 0;
38639 bevelSize = 0;
38640 bevelOffset = 0;
38641
38642 }
38643
38644 // Variables initialization
38645
38646 const shapePoints = shape.extractPoints( curveSegments );
38647
38648 let vertices = shapePoints.shape;
38649 const holes = shapePoints.holes;
38650
38651 const reverse = ! ShapeUtils.isClockWise( vertices );
38652
38653 if ( reverse ) {
38654
38655 vertices = vertices.reverse();
38656
38657 // Maybe we should also check if holes are in the opposite direction, just to be safe ...
38658
38659 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38660
38661 const ahole = holes[ h ];
38662
38663 if ( ShapeUtils.isClockWise( ahole ) ) {
38664
38665 holes[ h ] = ahole.reverse();
38666
38667 }
38668
38669 }
38670
38671 }
38672
38673
38674 const faces = ShapeUtils.triangulateShape( vertices, holes );
38675
38676 /* Vertices */
38677
38678 const contour = vertices; // vertices has all points but contour has only points of circumference
38679
38680 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38681
38682 const ahole = holes[ h ];
38683
38684 vertices = vertices.concat( ahole );
38685
38686 }
38687
38688
38689 function scalePt2( pt, vec, size ) {
38690
38691 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );
38692
38693 return pt.clone().addScaledVector( vec, size );
38694
38695 }
38696
38697 const vlen = vertices.length, flen = faces.length;
38698
38699
38700 // Find directions for point movement
38701
38702
38703 function getBevelVec( inPt, inPrev, inNext ) {
38704
38705 // computes for inPt the corresponding point inPt' on a new contour
38706 // shifted by 1 unit (length of normalized vector) to the left
38707 // if we walk along contour clockwise, this new contour is outside the old one
38708 //
38709 // inPt' is the intersection of the two lines parallel to the two
38710 // adjacent edges of inPt at a distance of 1 unit on the left side.
38711
38712 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt
38713
38714 // good reading for geometry algorithms (here: line-line intersection)
38715 // http://geomalgorithms.com/a05-_intersect-1.html
38716
38717 const v_prev_x = inPt.x - inPrev.x,
38718 v_prev_y = inPt.y - inPrev.y;
38719 const v_next_x = inNext.x - inPt.x,
38720 v_next_y = inNext.y - inPt.y;
38721
38723
38724 // check for collinear edges
38725 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );
38726
38727 if ( Math.abs( collinear0 ) > Number.EPSILON ) {
38728
38729 // not collinear
38730
38731 // length of vectors for normalizing
38732
38733 const v_prev_len = Math.sqrt( v_prev_lensq );
38734 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );
38735
38736 // shift adjacent points by unit vectors to the left
38737
38738 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );
38739 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );
38740
38741 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len );
38742 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len );
38743
38744 // scaling factor for v_prev to intersection point
38745
38746 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -
38749
38750 // vector from inPt to intersection point
38751
38752 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );
38753 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );
38754
38755 // Don't normalize!, otherwise sharp corners become ugly
38756 // but prevent crazy spikes
38758 if ( v_trans_lensq <= 2 ) {
38759
38760 return new Vector2( v_trans_x, v_trans_y );
38761
38762 } else {
38763
38764 shrink_by = Math.sqrt( v_trans_lensq / 2 );
38765
38766 }
38767
38768 } else {
38769
38770 // handle special case of collinear edges
38771
38772 let direction_eq = false; // assumes: opposite
38773
38774 if ( v_prev_x > Number.EPSILON ) {
38775
38776 if ( v_next_x > Number.EPSILON ) {
38777
38778 direction_eq = true;
38779
38780 }
38781
38782 } else {
38783
38784 if ( v_prev_x < - Number.EPSILON ) {
38785
38786 if ( v_next_x < - Number.EPSILON ) {
38787
38788 direction_eq = true;
38789
38790 }
38791
38792 } else {
38793
38794 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {
38795
38796 direction_eq = true;
38797
38798 }
38799
38800 }
38801
38802 }
38803
38804 if ( direction_eq ) {
38805
38806 // console.log("Warning: lines are a straight sequence");
38807 v_trans_x = - v_prev_y;
38809 shrink_by = Math.sqrt( v_prev_lensq );
38810
38811 } else {
38812
38813 // console.log("Warning: lines are a straight spike");
38816 shrink_by = Math.sqrt( v_prev_lensq / 2 );
38817
38818 }
38819
38820 }
38821
38822 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );
38823
38824 }
38825
38826
38827 const contourMovements = [];
38828
38829 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38830
38831 if ( j === il ) j = 0;
38832 if ( k === il ) k = 0;
38833
38834 // (j)---(i)---(k)
38835 // console.log('i,j,k', i, j , k)
38836
38838
38839 }
38840
38841 const holesMovements = [];
38843
38844 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38845
38846 const ahole = holes[ h ];
38847
38848 oneHoleMovements = [];
38849
38850 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {
38851
38852 if ( j === il ) j = 0;
38853 if ( k === il ) k = 0;
38854
38855 // (j)---(i)---(k)
38856 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );
38857
38858 }
38859
38862
38863 }
38864
38865
38866 // Loop bevelSegments, 1 for the front, 1 for the back
38867
38868 for ( let b = 0; b < bevelSegments; b ++ ) {
38869
38870 //for ( b = bevelSegments; b > 0; b -- ) {
38871
38872 const t = b / bevelSegments;
38873 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38874 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38875
38876 // contract shape
38877
38878 for ( let i = 0, il = contour.length; i < il; i ++ ) {
38879
38880 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38881
38882 v( vert.x, vert.y, - z );
38883
38884 }
38885
38886 // expand holes
38887
38888 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38889
38890 const ahole = holes[ h ];
38892
38893 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38894
38895 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38896
38897 v( vert.x, vert.y, - z );
38898
38899 }
38900
38901 }
38902
38903 }
38904
38905 const bs = bevelSize + bevelOffset;
38906
38907 // Back facing vertices
38908
38909 for ( let i = 0; i < vlen; i ++ ) {
38910
38911 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38912
38913 if ( ! extrudeByPath ) {
38914
38915 v( vert.x, vert.y, 0 );
38916
38917 } else {
38918
38919 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
38920
38921 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );
38922 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );
38923
38924 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );
38925
38926 v( position2.x, position2.y, position2.z );
38927
38928 }
38929
38930 }
38931
38932 // Add stepped vertices...
38933 // Including front facing vertices
38934
38935 for ( let s = 1; s <= steps; s ++ ) {
38936
38937 for ( let i = 0; i < vlen; i ++ ) {
38938
38939 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];
38940
38941 if ( ! extrudeByPath ) {
38942
38943 v( vert.x, vert.y, depth / steps * s );
38944
38945 } else {
38946
38947 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
38948
38949 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );
38950 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );
38951
38952 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal );
38953
38954 v( position2.x, position2.y, position2.z );
38955
38956 }
38957
38958 }
38959
38960 }
38961
38962
38963 // Add bevel segments planes
38964
38965 //for ( b = 1; b <= bevelSegments; b ++ ) {
38966 for ( let b = bevelSegments - 1; b >= 0; b -- ) {
38967
38968 const t = b / bevelSegments;
38969 const z = bevelThickness * Math.cos( t * Math.PI / 2 );
38970 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;
38971
38972 // contract shape
38973
38974 for ( let i = 0, il = contour.length; i < il; i ++ ) {
38975
38976 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs );
38977 v( vert.x, vert.y, depth + z );
38978
38979 }
38980
38981 // expand holes
38982
38983 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
38984
38985 const ahole = holes[ h ];
38987
38988 for ( let i = 0, il = ahole.length; i < il; i ++ ) {
38989
38990 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );
38991
38992 if ( ! extrudeByPath ) {
38993
38994 v( vert.x, vert.y, depth + z );
38995
38996 } else {
38997
38998 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );
38999
39000 }
39001
39002 }
39003
39004 }
39005
39006 }
39007
39008 /* Faces */
39009
39010 // Top and bottom faces
39011
39012 buildLidFaces();
39013
39014 // Sides faces
39015
39017
39018
39020
39021 function buildLidFaces() {
39022
39023 const start = verticesArray.length / 3;
39024
39025 if ( bevelEnabled ) {
39026
39027 let layer = 0; // steps + 1
39028 let offset = vlen * layer;
39029
39030 // Bottom faces
39031
39032 for ( let i = 0; i < flen; i ++ ) {
39033
39034 const face = faces[ i ];
39035 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );
39036
39037 }
39038
39039 layer = steps + bevelSegments * 2;
39040 offset = vlen * layer;
39041
39042 // Top faces
39043
39044 for ( let i = 0; i < flen; i ++ ) {
39045
39046 const face = faces[ i ];
39047 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );
39048
39049 }
39050
39051 } else {
39052
39053 // Bottom faces
39054
39055 for ( let i = 0; i < flen; i ++ ) {
39056
39057 const face = faces[ i ];
39058 f3( face[ 2 ], face[ 1 ], face[ 0 ] );
39059
39060 }
39061
39062 // Top faces
39063
39064 for ( let i = 0; i < flen; i ++ ) {
39065
39066 const face = faces[ i ];
39067 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );
39068
39069 }
39070
39071 }
39072
39073 scope.addGroup( start, verticesArray.length / 3 - start, 0 );
39074
39075 }
39076
39077 // Create faces for the z-sides of the shape
39078
39079 function buildSideFaces() {
39080
39081 const start = verticesArray.length / 3;
39082 let layeroffset = 0;
39084 layeroffset += contour.length;
39085
39086 for ( let h = 0, hl = holes.length; h < hl; h ++ ) {
39087
39088 const ahole = holes[ h ];
39090
39091 //, true
39092 layeroffset += ahole.length;
39093
39094 }
39095
39096
39097 scope.addGroup( start, verticesArray.length / 3 - start, 1 );
39098
39099
39100 }
39101
39102 function sidewalls( contour, layeroffset ) {
39103
39104 let i = contour.length;
39105
39106 while ( -- i >= 0 ) {
39107
39108 const j = i;
39109 let k = i - 1;
39110 if ( k < 0 ) k = contour.length - 1;
39111
39112 //console.log('b', i,j, i-1, k,vertices.length);
39113
39114 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {
39115
39116 const slen1 = vlen * s;
39117 const slen2 = vlen * ( s + 1 );
39118
39119 const a = layeroffset + j + slen1,
39120 b = layeroffset + k + slen1,
39121 c = layeroffset + k + slen2,
39122 d = layeroffset + j + slen2;
39123
39124 f4( a, b, c, d );
39125
39126 }
39127
39128 }
39129
39130 }
39131
39132 function v( x, y, z ) {
39133
39134 placeholder.push( x );
39135 placeholder.push( y );
39136 placeholder.push( z );
39137
39138 }
39139
39140
39141 function f3( a, b, c ) {
39142
39143 addVertex( a );
39144 addVertex( b );
39145 addVertex( c );
39146
39147 const nextIndex = verticesArray.length / 3;
39148 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39149
39150 addUV( uvs[ 0 ] );
39151 addUV( uvs[ 1 ] );
39152 addUV( uvs[ 2 ] );
39153
39154 }
39155
39156 function f4( a, b, c, d ) {
39157
39158 addVertex( a );
39159 addVertex( b );
39160 addVertex( d );
39161
39162 addVertex( b );
39163 addVertex( c );
39164 addVertex( d );
39165
39166
39167 const nextIndex = verticesArray.length / 3;
39168 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
39169
39170 addUV( uvs[ 0 ] );
39171 addUV( uvs[ 1 ] );
39172 addUV( uvs[ 3 ] );
39173
39174 addUV( uvs[ 1 ] );
39175 addUV( uvs[ 2 ] );
39176 addUV( uvs[ 3 ] );
39177
39178 }
39179
39180 function addVertex( index ) {
39181
39182 verticesArray.push( placeholder[ index * 3 + 0 ] );
39183 verticesArray.push( placeholder[ index * 3 + 1 ] );
39184 verticesArray.push( placeholder[ index * 3 + 2 ] );
39185
39186 }
39187
39188
39189 function addUV( vector2 ) {
39190
39191 uvArray.push( vector2.x );
39192 uvArray.push( vector2.y );
39193
39194 }
39195
39196 }
39197
39198 }
39199
39200 copy( source ) {
39201
39202 super.copy( source );
39203
39204 this.parameters = Object.assign( {}, source.parameters );
39205
39206 return this;
39207
39208 }
39209
39210 toJSON() {
39211
39212 const data = super.toJSON();
39213
39214 const shapes = this.parameters.shapes;
39215 const options = this.parameters.options;
39216
39217 return toJSON$1( shapes, options, data );
39218
39219 }
39220
39221 static fromJSON( data, shapes ) {
39222
39223 const geometryShapes = [];
39224
39225 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39226
39227 const shape = shapes[ data.shapes[ j ] ];
39228
39229 geometryShapes.push( shape );
39230
39231 }
39232
39233 const extrudePath = data.options.extrudePath;
39234
39235 if ( extrudePath !== undefined ) {
39236
39237 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );
39238
39239 }
39240
39241 return new ExtrudeGeometry( geometryShapes, data.options );
39242
39243 }
39244
39245 }
39246
39247 const WorldUVGenerator = {
39248
39250
39251 const a_x = vertices[ indexA * 3 ];
39252 const a_y = vertices[ indexA * 3 + 1 ];
39253 const b_x = vertices[ indexB * 3 ];
39254 const b_y = vertices[ indexB * 3 + 1 ];
39255 const c_x = vertices[ indexC * 3 ];
39256 const c_y = vertices[ indexC * 3 + 1 ];
39257
39258 return [
39259 new Vector2( a_x, a_y ),
39260 new Vector2( b_x, b_y ),
39261 new Vector2( c_x, c_y )
39262 ];
39263
39264 },
39265
39267
39268 const a_x = vertices[ indexA * 3 ];
39269 const a_y = vertices[ indexA * 3 + 1 ];
39270 const a_z = vertices[ indexA * 3 + 2 ];
39271 const b_x = vertices[ indexB * 3 ];
39272 const b_y = vertices[ indexB * 3 + 1 ];
39273 const b_z = vertices[ indexB * 3 + 2 ];
39274 const c_x = vertices[ indexC * 3 ];
39275 const c_y = vertices[ indexC * 3 + 1 ];
39276 const c_z = vertices[ indexC * 3 + 2 ];
39277 const d_x = vertices[ indexD * 3 ];
39278 const d_y = vertices[ indexD * 3 + 1 ];
39279 const d_z = vertices[ indexD * 3 + 2 ];
39280
39281 if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {
39282
39283 return [
39284 new Vector2( a_x, 1 - a_z ),
39285 new Vector2( b_x, 1 - b_z ),
39286 new Vector2( c_x, 1 - c_z ),
39287 new Vector2( d_x, 1 - d_z )
39288 ];
39289
39290 } else {
39291
39292 return [
39293 new Vector2( a_y, 1 - a_z ),
39294 new Vector2( b_y, 1 - b_z ),
39295 new Vector2( c_y, 1 - c_z ),
39296 new Vector2( d_y, 1 - d_z )
39297 ];
39298
39299 }
39300
39301 }
39302
39303 };
39304
39305 function toJSON$1( shapes, options, data ) {
39306
39307 data.shapes = [];
39308
39309 if ( Array.isArray( shapes ) ) {
39310
39311 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39312
39313 const shape = shapes[ i ];
39314
39315 data.shapes.push( shape.uuid );
39316
39317 }
39318
39319 } else {
39320
39321 data.shapes.push( shapes.uuid );
39322
39323 }
39324
39325 data.options = Object.assign( {}, options );
39326
39327 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();
39328
39329 return data;
39330
39331 }
39332
39334
39335 constructor( radius = 1, detail = 0 ) {
39336
39337 const t = ( 1 + Math.sqrt( 5 ) ) / 2;
39338
39339 const vertices = [
39340 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
39341 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
39342 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
39343 ];
39344
39345 const indices = [
39346 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
39347 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
39348 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
39349 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
39350 ];
39351
39353
39354 this.type = 'IcosahedronGeometry';
39355
39356 this.parameters = {
39357 radius: radius,
39358 detail: detail
39359 };
39360
39361 }
39362
39363 static fromJSON( data ) {
39364
39365 return new IcosahedronGeometry( data.radius, data.detail );
39366
39367 }
39368
39369 }
39370
39372
39373 constructor( radius = 1, detail = 0 ) {
39374
39375 const vertices = [
39376 1, 0, 0, - 1, 0, 0, 0, 1, 0,
39377 0, - 1, 0, 0, 0, 1, 0, 0, - 1
39378 ];
39379
39380 const indices = [
39381 0, 2, 4, 0, 4, 3, 0, 3, 5,
39382 0, 5, 2, 1, 2, 5, 1, 5, 3,
39383 1, 3, 4, 1, 4, 2
39384 ];
39385
39387
39388 this.type = 'OctahedronGeometry';
39389
39390 this.parameters = {
39391 radius: radius,
39392 detail: detail
39393 };
39394
39395 }
39396
39397 static fromJSON( data ) {
39398
39399 return new OctahedronGeometry( data.radius, data.detail );
39400
39401 }
39402
39403 }
39404
39405 class RingGeometry extends BufferGeometry {
39406
39407 constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {
39408
39409 super();
39410
39411 this.type = 'RingGeometry';
39412
39413 this.parameters = {
39420 };
39421
39422 thetaSegments = Math.max( 3, thetaSegments );
39423 phiSegments = Math.max( 1, phiSegments );
39424
39425 // buffers
39426
39427 const indices = [];
39428 const vertices = [];
39429 const normals = [];
39430 const uvs = [];
39431
39432 // some helper variables
39433
39435 const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
39436 const vertex = new Vector3();
39437 const uv = new Vector2();
39438
39439 // generate vertices, normals and uvs
39440
39441 for ( let j = 0; j <= phiSegments; j ++ ) {
39442
39443 for ( let i = 0; i <= thetaSegments; i ++ ) {
39444
39445 // values are generate from the inside of the ring to the outside
39446
39448
39449 // vertex
39450
39451 vertex.x = radius * Math.cos( segment );
39452 vertex.y = radius * Math.sin( segment );
39453
39454 vertices.push( vertex.x, vertex.y, vertex.z );
39455
39456 // normal
39457
39458 normals.push( 0, 0, 1 );
39459
39460 // uv
39461
39462 uv.x = ( vertex.x / outerRadius + 1 ) / 2;
39463 uv.y = ( vertex.y / outerRadius + 1 ) / 2;
39464
39465 uvs.push( uv.x, uv.y );
39466
39467 }
39468
39469 // increase the radius for next row of vertices
39470
39471 radius += radiusStep;
39472
39473 }
39474
39475 // indices
39476
39477 for ( let j = 0; j < phiSegments; j ++ ) {
39478
39479 const thetaSegmentLevel = j * ( thetaSegments + 1 );
39480
39481 for ( let i = 0; i < thetaSegments; i ++ ) {
39482
39483 const segment = i + thetaSegmentLevel;
39484
39485 const a = segment;
39486 const b = segment + thetaSegments + 1;
39487 const c = segment + thetaSegments + 2;
39488 const d = segment + 1;
39489
39490 // faces
39491
39492 indices.push( a, b, d );
39493 indices.push( b, c, d );
39494
39495 }
39496
39497 }
39498
39499 // build geometry
39500
39501 this.setIndex( indices );
39502 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39503 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39504 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39505
39506 }
39507
39508 copy( source ) {
39509
39510 super.copy( source );
39511
39512 this.parameters = Object.assign( {}, source.parameters );
39513
39514 return this;
39515
39516 }
39517
39518 static fromJSON( data ) {
39519
39520 return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength );
39521
39522 }
39523
39524 }
39525
39526 class ShapeGeometry extends BufferGeometry {
39527
39528 constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {
39529
39530 super();
39531
39532 this.type = 'ShapeGeometry';
39533
39534 this.parameters = {
39535 shapes: shapes,
39537 };
39538
39539 // buffers
39540
39541 const indices = [];
39542 const vertices = [];
39543 const normals = [];
39544 const uvs = [];
39545
39546 // helper variables
39547
39548 let groupStart = 0;
39549 let groupCount = 0;
39550
39551 // allow single and array values for "shapes" parameter
39552
39553 if ( Array.isArray( shapes ) === false ) {
39554
39555 addShape( shapes );
39556
39557 } else {
39558
39559 for ( let i = 0; i < shapes.length; i ++ ) {
39560
39561 addShape( shapes[ i ] );
39562
39563 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
39564
39566 groupCount = 0;
39567
39568 }
39569
39570 }
39571
39572 // build geometry
39573
39574 this.setIndex( indices );
39575 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39576 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39577 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39578
39579
39580 // helper functions
39581
39582 function addShape( shape ) {
39583
39584 const indexOffset = vertices.length / 3;
39585 const points = shape.extractPoints( curveSegments );
39586
39587 let shapeVertices = points.shape;
39588 const shapeHoles = points.holes;
39589
39590 // check direction of vertices
39591
39592 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
39593
39594 shapeVertices = shapeVertices.reverse();
39595
39596 }
39597
39598 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39599
39600 const shapeHole = shapeHoles[ i ];
39601
39602 if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
39603
39604 shapeHoles[ i ] = shapeHole.reverse();
39605
39606 }
39607
39608 }
39609
39610 const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
39611
39612 // join vertices of inner and outer paths to a single array
39613
39614 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
39615
39616 const shapeHole = shapeHoles[ i ];
39618
39619 }
39620
39621 // vertices, normals, uvs
39622
39623 for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
39624
39625 const vertex = shapeVertices[ i ];
39626
39627 vertices.push( vertex.x, vertex.y, 0 );
39628 normals.push( 0, 0, 1 );
39629 uvs.push( vertex.x, vertex.y ); // world uvs
39630
39631 }
39632
39633 // indices
39634
39635 for ( let i = 0, l = faces.length; i < l; i ++ ) {
39636
39637 const face = faces[ i ];
39638
39639 const a = face[ 0 ] + indexOffset;
39640 const b = face[ 1 ] + indexOffset;
39641 const c = face[ 2 ] + indexOffset;
39642
39643 indices.push( a, b, c );
39644 groupCount += 3;
39645
39646 }
39647
39648 }
39649
39650 }
39651
39652 copy( source ) {
39653
39654 super.copy( source );
39655
39656 this.parameters = Object.assign( {}, source.parameters );
39657
39658 return this;
39659
39660 }
39661
39662 toJSON() {
39663
39664 const data = super.toJSON();
39665
39666 const shapes = this.parameters.shapes;
39667
39668 return toJSON( shapes, data );
39669
39670 }
39671
39672 static fromJSON( data, shapes ) {
39673
39674 const geometryShapes = [];
39675
39676 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {
39677
39678 const shape = shapes[ data.shapes[ j ] ];
39679
39680 geometryShapes.push( shape );
39681
39682 }
39683
39684 return new ShapeGeometry( geometryShapes, data.curveSegments );
39685
39686 }
39687
39688 }
39689
39690 function toJSON( shapes, data ) {
39691
39692 data.shapes = [];
39693
39694 if ( Array.isArray( shapes ) ) {
39695
39696 for ( let i = 0, l = shapes.length; i < l; i ++ ) {
39697
39698 const shape = shapes[ i ];
39699
39700 data.shapes.push( shape.uuid );
39701
39702 }
39703
39704 } else {
39705
39706 data.shapes.push( shapes.uuid );
39707
39708 }
39709
39710 return data;
39711
39712 }
39713
39714 class SphereGeometry extends BufferGeometry {
39715
39716 constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {
39717
39718 super();
39719
39720 this.type = 'SphereGeometry';
39721
39722 this.parameters = {
39723 radius: radius,
39730 };
39731
39732 widthSegments = Math.max( 3, Math.floor( widthSegments ) );
39733 heightSegments = Math.max( 2, Math.floor( heightSegments ) );
39734
39735 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
39736
39737 let index = 0;
39738 const grid = [];
39739
39740 const vertex = new Vector3();
39741 const normal = new Vector3();
39742
39743 // buffers
39744
39745 const indices = [];
39746 const vertices = [];
39747 const normals = [];
39748 const uvs = [];
39749
39750 // generate vertices, normals and uvs
39751
39752 for ( let iy = 0; iy <= heightSegments; iy ++ ) {
39753
39754 const verticesRow = [];
39755
39756 const v = iy / heightSegments;
39757
39758 // special case for the poles
39759
39760 let uOffset = 0;
39761
39762 if ( iy === 0 && thetaStart === 0 ) {
39763
39764 uOffset = 0.5 / widthSegments;
39765
39766 } else if ( iy === heightSegments && thetaEnd === Math.PI ) {
39767
39768 uOffset = - 0.5 / widthSegments;
39769
39770 }
39771
39772 for ( let ix = 0; ix <= widthSegments; ix ++ ) {
39773
39774 const u = ix / widthSegments;
39775
39776 // vertex
39777
39778 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
39779 vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
39780 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
39781
39782 vertices.push( vertex.x, vertex.y, vertex.z );
39783
39784 // normal
39785
39786 normal.copy( vertex ).normalize();
39787 normals.push( normal.x, normal.y, normal.z );
39788
39789 // uv
39790
39791 uvs.push( u + uOffset, 1 - v );
39792
39793 verticesRow.push( index ++ );
39794
39795 }
39796
39797 grid.push( verticesRow );
39798
39799 }
39800
39801 // indices
39802
39803 for ( let iy = 0; iy < heightSegments; iy ++ ) {
39804
39805 for ( let ix = 0; ix < widthSegments; ix ++ ) {
39806
39807 const a = grid[ iy ][ ix + 1 ];
39808 const b = grid[ iy ][ ix ];
39809 const c = grid[ iy + 1 ][ ix ];
39810 const d = grid[ iy + 1 ][ ix + 1 ];
39811
39812 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
39813 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
39814
39815 }
39816
39817 }
39818
39819 // build geometry
39820
39821 this.setIndex( indices );
39822 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39823 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39824 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39825
39826 }
39827
39828 copy( source ) {
39829
39830 super.copy( source );
39831
39832 this.parameters = Object.assign( {}, source.parameters );
39833
39834 return this;
39835
39836 }
39837
39838 static fromJSON( data ) {
39839
39840 return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );
39841
39842 }
39843
39844 }
39845
39847
39848 constructor( radius = 1, detail = 0 ) {
39849
39850 const vertices = [
39851 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
39852 ];
39853
39854 const indices = [
39855 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
39856 ];
39857
39859
39860 this.type = 'TetrahedronGeometry';
39861
39862 this.parameters = {
39863 radius: radius,
39864 detail: detail
39865 };
39866
39867 }
39868
39869 static fromJSON( data ) {
39870
39871 return new TetrahedronGeometry( data.radius, data.detail );
39872
39873 }
39874
39875 }
39876
39877 class TorusGeometry extends BufferGeometry {
39878
39879 constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) {
39880
39881 super();
39882
39883 this.type = 'TorusGeometry';
39884
39885 this.parameters = {
39886 radius: radius,
39887 tube: tube,
39890 arc: arc
39891 };
39892
39895
39896 // buffers
39897
39898 const indices = [];
39899 const vertices = [];
39900 const normals = [];
39901 const uvs = [];
39902
39903 // helper variables
39904
39905 const center = new Vector3();
39906 const vertex = new Vector3();
39907 const normal = new Vector3();
39908
39909 // generate vertices, normals and uvs
39910
39911 for ( let j = 0; j <= radialSegments; j ++ ) {
39912
39913 for ( let i = 0; i <= tubularSegments; i ++ ) {
39914
39915 const u = i / tubularSegments * arc;
39916 const v = j / radialSegments * Math.PI * 2;
39917
39918 // vertex
39919
39920 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
39921 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
39922 vertex.z = tube * Math.sin( v );
39923
39924 vertices.push( vertex.x, vertex.y, vertex.z );
39925
39926 // normal
39927
39928 center.x = radius * Math.cos( u );
39929 center.y = radius * Math.sin( u );
39930 normal.subVectors( vertex, center ).normalize();
39931
39932 normals.push( normal.x, normal.y, normal.z );
39933
39934 // uv
39935
39936 uvs.push( i / tubularSegments );
39937 uvs.push( j / radialSegments );
39938
39939 }
39940
39941 }
39942
39943 // generate indices
39944
39945 for ( let j = 1; j <= radialSegments; j ++ ) {
39946
39947 for ( let i = 1; i <= tubularSegments; i ++ ) {
39948
39949 // indices
39950
39951 const a = ( tubularSegments + 1 ) * j + i - 1;
39952 const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
39953 const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
39954 const d = ( tubularSegments + 1 ) * j + i;
39955
39956 // faces
39957
39958 indices.push( a, b, d );
39959 indices.push( b, c, d );
39960
39961 }
39962
39963 }
39964
39965 // build geometry
39966
39967 this.setIndex( indices );
39968 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
39969 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
39970 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
39971
39972 }
39973
39974 copy( source ) {
39975
39976 super.copy( source );
39977
39978 this.parameters = Object.assign( {}, source.parameters );
39979
39980 return this;
39981
39982 }
39983
39984 static fromJSON( data ) {
39985
39986 return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc );
39987
39988 }
39989
39990 }
39991
39992 class TorusKnotGeometry extends BufferGeometry {
39993
39994 constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {
39995
39996 super();
39997
39998 this.type = 'TorusKnotGeometry';
39999
40000 this.parameters = {
40001 radius: radius,
40002 tube: tube,
40005 p: p,
40006 q: q
40007 };
40008
40011
40012 // buffers
40013
40014 const indices = [];
40015 const vertices = [];
40016 const normals = [];
40017 const uvs = [];
40018
40019 // helper variables
40020
40021 const vertex = new Vector3();
40022 const normal = new Vector3();
40023
40024 const P1 = new Vector3();
40025 const P2 = new Vector3();
40026
40027 const B = new Vector3();
40028 const T = new Vector3();
40029 const N = new Vector3();
40030
40031 // generate vertices, normals and uvs
40032
40033 for ( let i = 0; i <= tubularSegments; ++ i ) {
40034
40035 // the radian "u" is used to calculate the position on the torus curve of the current tubular segment
40036
40037 const u = i / tubularSegments * p * Math.PI * 2;
40038
40039 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
40040 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
40041
40043 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
40044
40045 // calculate orthonormal basis
40046
40047 T.subVectors( P2, P1 );
40048 N.addVectors( P2, P1 );
40049 B.crossVectors( T, N );
40050 N.crossVectors( B, T );
40051
40052 // normalize B, N. T can be ignored, we don't use it
40053
40054 B.normalize();
40055 N.normalize();
40056
40057 for ( let j = 0; j <= radialSegments; ++ j ) {
40058
40059 // now calculate the vertices. they are nothing more than an extrusion of the torus curve.
40060 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
40061
40062 const v = j / radialSegments * Math.PI * 2;
40063 const cx = - tube * Math.cos( v );
40064 const cy = tube * Math.sin( v );
40065
40066 // now calculate the final vertex position.
40067 // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve
40068
40069 vertex.x = P1.x + ( cx * N.x + cy * B.x );
40070 vertex.y = P1.y + ( cx * N.y + cy * B.y );
40071 vertex.z = P1.z + ( cx * N.z + cy * B.z );
40072
40073 vertices.push( vertex.x, vertex.y, vertex.z );
40074
40075 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
40076
40077 normal.subVectors( vertex, P1 ).normalize();
40078
40079 normals.push( normal.x, normal.y, normal.z );
40080
40081 // uv
40082
40083 uvs.push( i / tubularSegments );
40084 uvs.push( j / radialSegments );
40085
40086 }
40087
40088 }
40089
40090 // generate indices
40091
40092 for ( let j = 1; j <= tubularSegments; j ++ ) {
40093
40094 for ( let i = 1; i <= radialSegments; i ++ ) {
40095
40096 // indices
40097
40098 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40099 const b = ( radialSegments + 1 ) * j + ( i - 1 );
40100 const c = ( radialSegments + 1 ) * j + i;
40101 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40102
40103 // faces
40104
40105 indices.push( a, b, d );
40106 indices.push( b, c, d );
40107
40108 }
40109
40110 }
40111
40112 // build geometry
40113
40114 this.setIndex( indices );
40115 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40116 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40117 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40118
40119 // this function calculates the current position on the torus curve
40120
40121 function calculatePositionOnCurve( u, p, q, radius, position ) {
40122
40123 const cu = Math.cos( u );
40124 const su = Math.sin( u );
40125 const quOverP = q / p * u;
40126 const cs = Math.cos( quOverP );
40127
40128 position.x = radius * ( 2 + cs ) * 0.5 * cu;
40129 position.y = radius * ( 2 + cs ) * su * 0.5;
40130 position.z = radius * Math.sin( quOverP ) * 0.5;
40131
40132 }
40133
40134 }
40135
40136 copy( source ) {
40137
40138 super.copy( source );
40139
40140 this.parameters = Object.assign( {}, source.parameters );
40141
40142 return this;
40143
40144 }
40145
40146 static fromJSON( data ) {
40147
40148 return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q );
40149
40150 }
40151
40152 }
40153
40154 class TubeGeometry extends BufferGeometry {
40155
40156 constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) {
40157
40158 super();
40159
40160 this.type = 'TubeGeometry';
40161
40162 this.parameters = {
40163 path: path,
40165 radius: radius,
40167 closed: closed
40168 };
40169
40170 const frames = path.computeFrenetFrames( tubularSegments, closed );
40171
40172 // expose internals
40173
40174 this.tangents = frames.tangents;
40175 this.normals = frames.normals;
40176 this.binormals = frames.binormals;
40177
40178 // helper variables
40179
40180 const vertex = new Vector3();
40181 const normal = new Vector3();
40182 const uv = new Vector2();
40183 let P = new Vector3();
40184
40185 // buffer
40186
40187 const vertices = [];
40188 const normals = [];
40189 const uvs = [];
40190 const indices = [];
40191
40192 // create buffer data
40193
40195
40196 // build geometry
40197
40198 this.setIndex( indices );
40199 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40200 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
40201 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
40202
40203 // functions
40204
40205 function generateBufferData() {
40206
40207 for ( let i = 0; i < tubularSegments; i ++ ) {
40208
40209 generateSegment( i );
40210
40211 }
40212
40213 // if the geometry is not closed, generate the last row of vertices and normals
40214 // at the regular position on the given path
40215 //
40216 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
40217
40218 generateSegment( ( closed === false ) ? tubularSegments : 0 );
40219
40220 // uvs are generated in a separate function.
40221 // this makes it easy compute correct values for closed geometries
40222
40223 generateUVs();
40224
40225 // finally create faces
40226
40228
40229 }
40230
40231 function generateSegment( i ) {
40232
40233 // we use getPointAt to sample evenly distributed points from the given path
40234
40235 P = path.getPointAt( i / tubularSegments, P );
40236
40237 // retrieve corresponding normal and binormal
40238
40239 const N = frames.normals[ i ];
40240 const B = frames.binormals[ i ];
40241
40242 // generate normals and vertices for the current segment
40243
40244 for ( let j = 0; j <= radialSegments; j ++ ) {
40245
40246 const v = j / radialSegments * Math.PI * 2;
40247
40248 const sin = Math.sin( v );
40249 const cos = - Math.cos( v );
40250
40251 // normal
40252
40253 normal.x = ( cos * N.x + sin * B.x );
40254 normal.y = ( cos * N.y + sin * B.y );
40255 normal.z = ( cos * N.z + sin * B.z );
40256 normal.normalize();
40257
40258 normals.push( normal.x, normal.y, normal.z );
40259
40260 // vertex
40261
40262 vertex.x = P.x + radius * normal.x;
40263 vertex.y = P.y + radius * normal.y;
40264 vertex.z = P.z + radius * normal.z;
40265
40266 vertices.push( vertex.x, vertex.y, vertex.z );
40267
40268 }
40269
40270 }
40271
40272 function generateIndices() {
40273
40274 for ( let j = 1; j <= tubularSegments; j ++ ) {
40275
40276 for ( let i = 1; i <= radialSegments; i ++ ) {
40277
40278 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
40279 const b = ( radialSegments + 1 ) * j + ( i - 1 );
40280 const c = ( radialSegments + 1 ) * j + i;
40281 const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
40282
40283 // faces
40284
40285 indices.push( a, b, d );
40286 indices.push( b, c, d );
40287
40288 }
40289
40290 }
40291
40292 }
40293
40294 function generateUVs() {
40295
40296 for ( let i = 0; i <= tubularSegments; i ++ ) {
40297
40298 for ( let j = 0; j <= radialSegments; j ++ ) {
40299
40300 uv.x = i / tubularSegments;
40301 uv.y = j / radialSegments;
40302
40303 uvs.push( uv.x, uv.y );
40304
40305 }
40306
40307 }
40308
40309 }
40310
40311 }
40312
40313 copy( source ) {
40314
40315 super.copy( source );
40316
40317 this.parameters = Object.assign( {}, source.parameters );
40318
40319 return this;
40320
40321 }
40322
40323 toJSON() {
40324
40325 const data = super.toJSON();
40326
40327 data.path = this.parameters.path.toJSON();
40328
40329 return data;
40330
40331 }
40332
40333 static fromJSON( data ) {
40334
40335 // This only works for built-in curves (e.g. CatmullRomCurve3).
40336 // User defined curves or instances of CurvePath will not be deserialized.
40337 return new TubeGeometry(
40338 new Curves[ data.path.type ]().fromJSON( data.path ),
40339 data.tubularSegments,
40340 data.radius,
40341 data.radialSegments,
40342 data.closed
40343 );
40344
40345 }
40346
40347 }
40348
40349 class WireframeGeometry extends BufferGeometry {
40350
40351 constructor( geometry = null ) {
40352
40353 super();
40354
40355 this.type = 'WireframeGeometry';
40356
40357 this.parameters = {
40359 };
40360
40361 if ( geometry !== null ) {
40362
40363 // buffer
40364
40365 const vertices = [];
40366 const edges = new Set();
40367
40368 // helper variables
40369
40370 const start = new Vector3();
40371 const end = new Vector3();
40372
40373 if ( geometry.index !== null ) {
40374
40375 // indexed BufferGeometry
40376
40377 const position = geometry.attributes.position;
40378 const indices = geometry.index;
40379 let groups = geometry.groups;
40380
40381 if ( groups.length === 0 ) {
40382
40383 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
40384
40385 }
40386
40387 // create a data structure that contains all edges without duplicates
40388
40389 for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
40390
40391 const group = groups[ o ];
40392
40393 const groupStart = group.start;
40394 const groupCount = group.count;
40395
40396 for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {
40397
40398 for ( let j = 0; j < 3; j ++ ) {
40399
40400 const index1 = indices.getX( i + j );
40401 const index2 = indices.getX( i + ( j + 1 ) % 3 );
40402
40403 start.fromBufferAttribute( position, index1 );
40404 end.fromBufferAttribute( position, index2 );
40405
40406 if ( isUniqueEdge( start, end, edges ) === true ) {
40407
40408 vertices.push( start.x, start.y, start.z );
40409 vertices.push( end.x, end.y, end.z );
40410
40411 }
40412
40413 }
40414
40415 }
40416
40417 }
40418
40419 } else {
40420
40421 // non-indexed BufferGeometry
40422
40423 const position = geometry.attributes.position;
40424
40425 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
40426
40427 for ( let j = 0; j < 3; j ++ ) {
40428
40429 // three edges per triangle, an edge is represented as (index1, index2)
40430 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
40431
40432 const index1 = 3 * i + j;
40433 const index2 = 3 * i + ( ( j + 1 ) % 3 );
40434
40435 start.fromBufferAttribute( position, index1 );
40436 end.fromBufferAttribute( position, index2 );
40437
40438 if ( isUniqueEdge( start, end, edges ) === true ) {
40439
40440 vertices.push( start.x, start.y, start.z );
40441 vertices.push( end.x, end.y, end.z );
40442
40443 }
40444
40445 }
40446
40447 }
40448
40449 }
40450
40451 // build geometry
40452
40453 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
40454
40455 }
40456
40457 }
40458
40459 copy( source ) {
40460
40461 super.copy( source );
40462
40463 this.parameters = Object.assign( {}, source.parameters );
40464
40465 return this;
40466
40467 }
40468
40469 }
40470
40471 function isUniqueEdge( start, end, edges ) {
40472
40473 const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;
40474 const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge
40475
40476 if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {
40477
40478 return false;
40479
40480 } else {
40481
40482 edges.add( hash1 );
40483 edges.add( hash2 );
40484 return true;
40485
40486 }
40487
40488 }
40489
40490 var Geometries = /*#__PURE__*/Object.freeze({
40491 __proto__: null,
40513 });
40514
40515 class ShadowMaterial extends Material {
40516
40518
40519 super();
40520
40521 this.isShadowMaterial = true;
40522
40523 this.type = 'ShadowMaterial';
40524
40525 this.color = new Color( 0x000000 );
40526 this.transparent = true;
40527
40528 this.fog = true;
40529
40530 this.setValues( parameters );
40531
40532 }
40533
40534 copy( source ) {
40535
40536 super.copy( source );
40537
40538 this.color.copy( source.color );
40539
40540 this.fog = source.fog;
40541
40542 return this;
40543
40544 }
40545
40546 }
40547
40548 class RawShaderMaterial extends ShaderMaterial {
40549
40550 constructor( parameters ) {
40551
40552 super( parameters );
40553
40554 this.isRawShaderMaterial = true;
40555
40556 this.type = 'RawShaderMaterial';
40557
40558 }
40559
40560 }
40561
40562 class MeshStandardMaterial extends Material {
40563
40565
40566 super();
40567
40568 this.isMeshStandardMaterial = true;
40569
40570 this.defines = { 'STANDARD': '' };
40571
40572 this.type = 'MeshStandardMaterial';
40573
40574 this.color = new Color( 0xffffff ); // diffuse
40575 this.roughness = 1.0;
40576 this.metalness = 0.0;
40577
40578 this.map = null;
40579
40580 this.lightMap = null;
40581 this.lightMapIntensity = 1.0;
40582
40583 this.aoMap = null;
40584 this.aoMapIntensity = 1.0;
40585
40586 this.emissive = new Color( 0x000000 );
40587 this.emissiveIntensity = 1.0;
40588 this.emissiveMap = null;
40589
40590 this.bumpMap = null;
40591 this.bumpScale = 1;
40592
40593 this.normalMap = null;
40595 this.normalScale = new Vector2( 1, 1 );
40596
40597 this.displacementMap = null;
40598 this.displacementScale = 1;
40599 this.displacementBias = 0;
40600
40601 this.roughnessMap = null;
40602
40603 this.metalnessMap = null;
40604
40605 this.alphaMap = null;
40606
40607 this.envMap = null;
40608 this.envMapIntensity = 1.0;
40609
40610 this.wireframe = false;
40611 this.wireframeLinewidth = 1;
40612 this.wireframeLinecap = 'round';
40613 this.wireframeLinejoin = 'round';
40614
40615 this.flatShading = false;
40616
40617 this.fog = true;
40618
40619 this.setValues( parameters );
40620
40621 }
40622
40623 copy( source ) {
40624
40625 super.copy( source );
40626
40627 this.defines = { 'STANDARD': '' };
40628
40629 this.color.copy( source.color );
40630 this.roughness = source.roughness;
40631 this.metalness = source.metalness;
40632
40633 this.map = source.map;
40634
40635 this.lightMap = source.lightMap;
40636 this.lightMapIntensity = source.lightMapIntensity;
40637
40638 this.aoMap = source.aoMap;
40639 this.aoMapIntensity = source.aoMapIntensity;
40640
40641 this.emissive.copy( source.emissive );
40642 this.emissiveMap = source.emissiveMap;
40643 this.emissiveIntensity = source.emissiveIntensity;
40644
40645 this.bumpMap = source.bumpMap;
40646 this.bumpScale = source.bumpScale;
40647
40648 this.normalMap = source.normalMap;
40649 this.normalMapType = source.normalMapType;
40650 this.normalScale.copy( source.normalScale );
40651
40652 this.displacementMap = source.displacementMap;
40653 this.displacementScale = source.displacementScale;
40654 this.displacementBias = source.displacementBias;
40655
40656 this.roughnessMap = source.roughnessMap;
40657
40658 this.metalnessMap = source.metalnessMap;
40659
40660 this.alphaMap = source.alphaMap;
40661
40662 this.envMap = source.envMap;
40663 this.envMapIntensity = source.envMapIntensity;
40664
40665 this.wireframe = source.wireframe;
40666 this.wireframeLinewidth = source.wireframeLinewidth;
40667 this.wireframeLinecap = source.wireframeLinecap;
40668 this.wireframeLinejoin = source.wireframeLinejoin;
40669
40670 this.flatShading = source.flatShading;
40671
40672 this.fog = source.fog;
40673
40674 return this;
40675
40676 }
40677
40678 }
40679
40681
40682 constructor( parameters ) {
40683
40684 super();
40685
40686 this.isMeshPhysicalMaterial = true;
40687
40688 this.defines = {
40689
40690 'STANDARD': '',
40691 'PHYSICAL': ''
40692
40693 };
40694
40695 this.type = 'MeshPhysicalMaterial';
40696
40697 this.anisotropyRotation = 0;
40698 this.anisotropyMap = null;
40699
40700 this.clearcoatMap = null;
40701 this.clearcoatRoughness = 0.0;
40702 this.clearcoatRoughnessMap = null;
40703 this.clearcoatNormalScale = new Vector2( 1, 1 );
40704 this.clearcoatNormalMap = null;
40705
40706 this.ior = 1.5;
40707
40708 Object.defineProperty( this, 'reflectivity', {
40709 get: function () {
40710
40711 return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );
40712
40713 },
40714 set: function ( reflectivity ) {
40715
40716 this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );
40717
40718 }
40719 } );
40720
40721 this.iridescenceMap = null;
40722 this.iridescenceIOR = 1.3;
40723 this.iridescenceThicknessRange = [ 100, 400 ];
40724 this.iridescenceThicknessMap = null;
40725
40726 this.sheenColor = new Color( 0x000000 );
40727 this.sheenColorMap = null;
40728 this.sheenRoughness = 1.0;
40729 this.sheenRoughnessMap = null;
40730
40731 this.transmissionMap = null;
40732
40733 this.thickness = 0;
40734 this.thicknessMap = null;
40736 this.attenuationColor = new Color( 1, 1, 1 );
40737
40738 this.specularIntensity = 1.0;
40739 this.specularIntensityMap = null;
40740 this.specularColor = new Color( 1, 1, 1 );
40741 this.specularColorMap = null;
40742
40743 this._anisotropy = 0;
40744 this._clearcoat = 0;
40745 this._iridescence = 0;
40746 this._sheen = 0.0;
40747 this._transmission = 0;
40748
40749 this.setValues( parameters );
40750
40751 }
40752
40753 get anisotropy() {
40754
40755 return this._anisotropy;
40756
40757 }
40758
40759 set anisotropy( value ) {
40760
40761 if ( this._anisotropy > 0 !== value > 0 ) {
40762
40763 this.version ++;
40764
40765 }
40766
40767 this._anisotropy = value;
40768
40769 }
40770
40771 get clearcoat() {
40772
40773 return this._clearcoat;
40774
40775 }
40776
40777 set clearcoat( value ) {
40778
40779 if ( this._clearcoat > 0 !== value > 0 ) {
40780
40781 this.version ++;
40782
40783 }
40784
40785 this._clearcoat = value;
40786
40787 }
40788
40789 get iridescence() {
40790
40791 return this._iridescence;
40792
40793 }
40794
40795 set iridescence( value ) {
40796
40797 if ( this._iridescence > 0 !== value > 0 ) {
40798
40799 this.version ++;
40800
40801 }
40802
40803 this._iridescence = value;
40804
40805 }
40806
40807 get sheen() {
40808
40809 return this._sheen;
40810
40811 }
40812
40813 set sheen( value ) {
40814
40815 if ( this._sheen > 0 !== value > 0 ) {
40816
40817 this.version ++;
40818
40819 }
40820
40821 this._sheen = value;
40822
40823 }
40824
40825 get transmission() {
40826
40827 return this._transmission;
40828
40829 }
40830
40831 set transmission( value ) {
40832
40833 if ( this._transmission > 0 !== value > 0 ) {
40834
40835 this.version ++;
40836
40837 }
40838
40839 this._transmission = value;
40840
40841 }
40842
40843 copy( source ) {
40844
40845 super.copy( source );
40846
40847 this.defines = {
40848
40849 'STANDARD': '',
40850 'PHYSICAL': ''
40851
40852 };
40853
40854 this.anisotropy = source.anisotropy;
40855 this.anisotropyRotation = source.anisotropyRotation;
40856 this.anisotropyMap = source.anisotropyMap;
40857
40858 this.clearcoat = source.clearcoat;
40859 this.clearcoatMap = source.clearcoatMap;
40860 this.clearcoatRoughness = source.clearcoatRoughness;
40861 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
40862 this.clearcoatNormalMap = source.clearcoatNormalMap;
40863 this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
40864
40865 this.ior = source.ior;
40866
40867 this.iridescence = source.iridescence;
40868 this.iridescenceMap = source.iridescenceMap;
40869 this.iridescenceIOR = source.iridescenceIOR;
40870 this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];
40871 this.iridescenceThicknessMap = source.iridescenceThicknessMap;
40872
40873 this.sheen = source.sheen;
40874 this.sheenColor.copy( source.sheenColor );
40875 this.sheenColorMap = source.sheenColorMap;
40876 this.sheenRoughness = source.sheenRoughness;
40877 this.sheenRoughnessMap = source.sheenRoughnessMap;
40878
40879 this.transmission = source.transmission;
40880 this.transmissionMap = source.transmissionMap;
40881
40882 this.thickness = source.thickness;
40883 this.thicknessMap = source.thicknessMap;
40884 this.attenuationDistance = source.attenuationDistance;
40885 this.attenuationColor.copy( source.attenuationColor );
40886
40887 this.specularIntensity = source.specularIntensity;
40888 this.specularIntensityMap = source.specularIntensityMap;
40889 this.specularColor.copy( source.specularColor );
40890 this.specularColorMap = source.specularColorMap;
40891
40892 return this;
40893
40894 }
40895
40896 }
40897
40898 class MeshPhongMaterial extends Material {
40899
40900 constructor( parameters ) {
40901
40902 super();
40903
40904 this.isMeshPhongMaterial = true;
40905
40906 this.type = 'MeshPhongMaterial';
40907
40908 this.color = new Color( 0xffffff ); // diffuse
40909 this.specular = new Color( 0x111111 );
40910 this.shininess = 30;
40911
40912 this.map = null;
40913
40914 this.lightMap = null;
40915 this.lightMapIntensity = 1.0;
40916
40917 this.aoMap = null;
40918 this.aoMapIntensity = 1.0;
40919
40920 this.emissive = new Color( 0x000000 );
40921 this.emissiveIntensity = 1.0;
40922 this.emissiveMap = null;
40923
40924 this.bumpMap = null;
40925 this.bumpScale = 1;
40926
40927 this.normalMap = null;
40929 this.normalScale = new Vector2( 1, 1 );
40930
40931 this.displacementMap = null;
40932 this.displacementScale = 1;
40933 this.displacementBias = 0;
40934
40935 this.specularMap = null;
40936
40937 this.alphaMap = null;
40938
40939 this.envMap = null;
40941 this.reflectivity = 1;
40942 this.refractionRatio = 0.98;
40943
40944 this.wireframe = false;
40945 this.wireframeLinewidth = 1;
40946 this.wireframeLinecap = 'round';
40947 this.wireframeLinejoin = 'round';
40948
40949 this.flatShading = false;
40950
40951 this.fog = true;
40952
40953 this.setValues( parameters );
40954
40955 }
40956
40957 copy( source ) {
40958
40959 super.copy( source );
40960
40961 this.color.copy( source.color );
40962 this.specular.copy( source.specular );
40963 this.shininess = source.shininess;
40964
40965 this.map = source.map;
40966
40967 this.lightMap = source.lightMap;
40968 this.lightMapIntensity = source.lightMapIntensity;
40969
40970 this.aoMap = source.aoMap;
40971 this.aoMapIntensity = source.aoMapIntensity;
40972
40973 this.emissive.copy( source.emissive );
40974 this.emissiveMap = source.emissiveMap;
40975 this.emissiveIntensity = source.emissiveIntensity;
40976
40977 this.bumpMap = source.bumpMap;
40978 this.bumpScale = source.bumpScale;
40979
40980 this.normalMap = source.normalMap;
40981 this.normalMapType = source.normalMapType;
40982 this.normalScale.copy( source.normalScale );
40983
40984 this.displacementMap = source.displacementMap;
40985 this.displacementScale = source.displacementScale;
40986 this.displacementBias = source.displacementBias;
40987
40988 this.specularMap = source.specularMap;
40989
40990 this.alphaMap = source.alphaMap;
40991
40992 this.envMap = source.envMap;
40993 this.combine = source.combine;
40994 this.reflectivity = source.reflectivity;
40995 this.refractionRatio = source.refractionRatio;
40996
40997 this.wireframe = source.wireframe;
40998 this.wireframeLinewidth = source.wireframeLinewidth;
40999 this.wireframeLinecap = source.wireframeLinecap;
41000 this.wireframeLinejoin = source.wireframeLinejoin;
41001
41002 this.flatShading = source.flatShading;
41003
41004 this.fog = source.fog;
41005
41006 return this;
41007
41008 }
41009
41010 }
41011
41012 class MeshToonMaterial extends Material {
41013
41014 constructor( parameters ) {
41015
41016 super();
41017
41018 this.isMeshToonMaterial = true;
41019
41020 this.defines = { 'TOON': '' };
41021
41022 this.type = 'MeshToonMaterial';
41023
41024 this.color = new Color( 0xffffff );
41025
41026 this.map = null;
41027 this.gradientMap = null;
41028
41029 this.lightMap = null;
41030 this.lightMapIntensity = 1.0;
41031
41032 this.aoMap = null;
41033 this.aoMapIntensity = 1.0;
41034
41035 this.emissive = new Color( 0x000000 );
41036 this.emissiveIntensity = 1.0;
41037 this.emissiveMap = null;
41038
41039 this.bumpMap = null;
41040 this.bumpScale = 1;
41041
41042 this.normalMap = null;
41044 this.normalScale = new Vector2( 1, 1 );
41045
41046 this.displacementMap = null;
41047 this.displacementScale = 1;
41048 this.displacementBias = 0;
41049
41050 this.alphaMap = null;
41051
41052 this.wireframe = false;
41053 this.wireframeLinewidth = 1;
41054 this.wireframeLinecap = 'round';
41055 this.wireframeLinejoin = 'round';
41056
41057 this.fog = true;
41058
41059 this.setValues( parameters );
41060
41061 }
41062
41063 copy( source ) {
41064
41065 super.copy( source );
41066
41067 this.color.copy( source.color );
41068
41069 this.map = source.map;
41070 this.gradientMap = source.gradientMap;
41071
41072 this.lightMap = source.lightMap;
41073 this.lightMapIntensity = source.lightMapIntensity;
41074
41075 this.aoMap = source.aoMap;
41076 this.aoMapIntensity = source.aoMapIntensity;
41077
41078 this.emissive.copy( source.emissive );
41079 this.emissiveMap = source.emissiveMap;
41080 this.emissiveIntensity = source.emissiveIntensity;
41081
41082 this.bumpMap = source.bumpMap;
41083 this.bumpScale = source.bumpScale;
41084
41085 this.normalMap = source.normalMap;
41086 this.normalMapType = source.normalMapType;
41087 this.normalScale.copy( source.normalScale );
41088
41089 this.displacementMap = source.displacementMap;
41090 this.displacementScale = source.displacementScale;
41091 this.displacementBias = source.displacementBias;
41092
41093 this.alphaMap = source.alphaMap;
41094
41095 this.wireframe = source.wireframe;
41096 this.wireframeLinewidth = source.wireframeLinewidth;
41097 this.wireframeLinecap = source.wireframeLinecap;
41098 this.wireframeLinejoin = source.wireframeLinejoin;
41099
41100 this.fog = source.fog;
41101
41102 return this;
41103
41104 }
41105
41106 }
41107
41108 class MeshNormalMaterial extends Material {
41109
41110 constructor( parameters ) {
41111
41112 super();
41113
41114 this.isMeshNormalMaterial = true;
41115
41116 this.type = 'MeshNormalMaterial';
41117
41118 this.bumpMap = null;
41119 this.bumpScale = 1;
41120
41121 this.normalMap = null;
41123 this.normalScale = new Vector2( 1, 1 );
41124
41125 this.displacementMap = null;
41126 this.displacementScale = 1;
41127 this.displacementBias = 0;
41128
41129 this.wireframe = false;
41130 this.wireframeLinewidth = 1;
41131
41132 this.flatShading = false;
41133
41134 this.setValues( parameters );
41135
41136 }
41137
41138 copy( source ) {
41139
41140 super.copy( source );
41141
41142 this.bumpMap = source.bumpMap;
41143 this.bumpScale = source.bumpScale;
41144
41145 this.normalMap = source.normalMap;
41146 this.normalMapType = source.normalMapType;
41147 this.normalScale.copy( source.normalScale );
41148
41149 this.displacementMap = source.displacementMap;
41150 this.displacementScale = source.displacementScale;
41151 this.displacementBias = source.displacementBias;
41152
41153 this.wireframe = source.wireframe;
41154 this.wireframeLinewidth = source.wireframeLinewidth;
41155
41156 this.flatShading = source.flatShading;
41157
41158 return this;
41159
41160 }
41161
41162 }
41163
41164 class MeshLambertMaterial extends Material {
41165
41166 constructor( parameters ) {
41167
41168 super();
41169
41170 this.isMeshLambertMaterial = true;
41171
41172 this.type = 'MeshLambertMaterial';
41173
41174 this.color = new Color( 0xffffff ); // diffuse
41175
41176 this.map = null;
41177
41178 this.lightMap = null;
41179 this.lightMapIntensity = 1.0;
41180
41181 this.aoMap = null;
41182 this.aoMapIntensity = 1.0;
41183
41184 this.emissive = new Color( 0x000000 );
41185 this.emissiveIntensity = 1.0;
41186 this.emissiveMap = null;
41187
41188 this.bumpMap = null;
41189 this.bumpScale = 1;
41190
41191 this.normalMap = null;
41193 this.normalScale = new Vector2( 1, 1 );
41194
41195 this.displacementMap = null;
41196 this.displacementScale = 1;
41197 this.displacementBias = 0;
41198
41199 this.specularMap = null;
41200
41201 this.alphaMap = null;
41202
41203 this.envMap = null;
41205 this.reflectivity = 1;
41206 this.refractionRatio = 0.98;
41207
41208 this.wireframe = false;
41209 this.wireframeLinewidth = 1;
41210 this.wireframeLinecap = 'round';
41211 this.wireframeLinejoin = 'round';
41212
41213 this.flatShading = false;
41214
41215 this.fog = true;
41216
41217 this.setValues( parameters );
41218
41219 }
41220
41221 copy( source ) {
41222
41223 super.copy( source );
41224
41225 this.color.copy( source.color );
41226
41227 this.map = source.map;
41228
41229 this.lightMap = source.lightMap;
41230 this.lightMapIntensity = source.lightMapIntensity;
41231
41232 this.aoMap = source.aoMap;
41233 this.aoMapIntensity = source.aoMapIntensity;
41234
41235 this.emissive.copy( source.emissive );
41236 this.emissiveMap = source.emissiveMap;
41237 this.emissiveIntensity = source.emissiveIntensity;
41238
41239 this.bumpMap = source.bumpMap;
41240 this.bumpScale = source.bumpScale;
41241
41242 this.normalMap = source.normalMap;
41243 this.normalMapType = source.normalMapType;
41244 this.normalScale.copy( source.normalScale );
41245
41246 this.displacementMap = source.displacementMap;
41247 this.displacementScale = source.displacementScale;
41248 this.displacementBias = source.displacementBias;
41249
41250 this.specularMap = source.specularMap;
41251
41252 this.alphaMap = source.alphaMap;
41253
41254 this.envMap = source.envMap;
41255 this.combine = source.combine;
41256 this.reflectivity = source.reflectivity;
41257 this.refractionRatio = source.refractionRatio;
41258
41259 this.wireframe = source.wireframe;
41260 this.wireframeLinewidth = source.wireframeLinewidth;
41261 this.wireframeLinecap = source.wireframeLinecap;
41262 this.wireframeLinejoin = source.wireframeLinejoin;
41263
41264 this.flatShading = source.flatShading;
41265
41266 this.fog = source.fog;
41267
41268 return this;
41269
41270 }
41271
41272 }
41273
41274 class MeshMatcapMaterial extends Material {
41275
41276 constructor( parameters ) {
41277
41278 super();
41279
41280 this.isMeshMatcapMaterial = true;
41281
41282 this.defines = { 'MATCAP': '' };
41283
41284 this.type = 'MeshMatcapMaterial';
41285
41286 this.color = new Color( 0xffffff ); // diffuse
41287
41288 this.matcap = null;
41289
41290 this.map = null;
41291
41292 this.bumpMap = null;
41293 this.bumpScale = 1;
41294
41295 this.normalMap = null;
41297 this.normalScale = new Vector2( 1, 1 );
41298
41299 this.displacementMap = null;
41300 this.displacementScale = 1;
41301 this.displacementBias = 0;
41302
41303 this.alphaMap = null;
41304
41305 this.flatShading = false;
41306
41307 this.fog = true;
41308
41309 this.setValues( parameters );
41310
41311 }
41312
41313
41314 copy( source ) {
41315
41316 super.copy( source );
41317
41318 this.defines = { 'MATCAP': '' };
41319
41320 this.color.copy( source.color );
41321
41322 this.matcap = source.matcap;
41323
41324 this.map = source.map;
41325
41326 this.bumpMap = source.bumpMap;
41327 this.bumpScale = source.bumpScale;
41328
41329 this.normalMap = source.normalMap;
41330 this.normalMapType = source.normalMapType;
41331 this.normalScale.copy( source.normalScale );
41332
41333 this.displacementMap = source.displacementMap;
41334 this.displacementScale = source.displacementScale;
41335 this.displacementBias = source.displacementBias;
41336
41337 this.alphaMap = source.alphaMap;
41338
41339 this.flatShading = source.flatShading;
41340
41341 this.fog = source.fog;
41342
41343 return this;
41344
41345 }
41346
41347 }
41348
41350
41351 constructor( parameters ) {
41352
41353 super();
41354
41355 this.isLineDashedMaterial = true;
41356
41357 this.type = 'LineDashedMaterial';
41358
41359 this.scale = 1;
41360 this.dashSize = 3;
41361 this.gapSize = 1;
41362
41363 this.setValues( parameters );
41364
41365 }
41366
41367 copy( source ) {
41368
41369 super.copy( source );
41370
41371 this.scale = source.scale;
41372 this.dashSize = source.dashSize;
41373 this.gapSize = source.gapSize;
41374
41375 return this;
41376
41377 }
41378
41379 }
41380
41381 // converts an array to a specific type
41382 function convertArray( array, type, forceClone ) {
41383
41384 if ( ! array || // let 'undefined' and 'null' pass
41385 ! forceClone && array.constructor === type ) return array;
41386
41387 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) {
41388
41389 return new type( array ); // create typed array
41390
41391 }
41392
41393 return Array.prototype.slice.call( array ); // create Array
41394
41395 }
41396
41397 function isTypedArray( object ) {
41398
41399 return ArrayBuffer.isView( object ) &&
41400 ! ( object instanceof DataView );
41401
41402 }
41403
41404 // returns an array by which times and values can be sorted
41405 function getKeyframeOrder( times ) {
41406
41407 function compareTime( i, j ) {
41408
41409 return times[ i ] - times[ j ];
41410
41411 }
41412
41413 const n = times.length;
41414 const result = new Array( n );
41415 for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
41416
41417 result.sort( compareTime );
41418
41419 return result;
41420
41421 }
41422
41423 // uses the array previously returned by 'getKeyframeOrder' to sort data
41424 function sortedArray( values, stride, order ) {
41425
41426 const nValues = values.length;
41427 const result = new values.constructor( nValues );
41428
41429 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {
41430
41431 const srcOffset = order[ i ] * stride;
41432
41433 for ( let j = 0; j !== stride; ++ j ) {
41434
41435 result[ dstOffset ++ ] = values[ srcOffset + j ];
41436
41437 }
41438
41439 }
41440
41441 return result;
41442
41443 }
41444
41445 // function for parsing AOS keyframe formats
41447
41448 let i = 1, key = jsonKeys[ 0 ];
41449
41450 while ( key !== undefined && key[ valuePropertyName ] === undefined ) {
41451
41452 key = jsonKeys[ i ++ ];
41453
41454 }
41455
41456 if ( key === undefined ) return; // no data
41457
41459 if ( value === undefined ) return; // no data
41460
41461 if ( Array.isArray( value ) ) {
41462
41463 do {
41464
41466
41467 if ( value !== undefined ) {
41468
41469 times.push( key.time );
41470 values.push.apply( values, value ); // push all elements
41471
41472 }
41473
41474 key = jsonKeys[ i ++ ];
41475
41476 } while ( key !== undefined );
41477
41478 } else if ( value.toArray !== undefined ) {
41479
41480 // ...assume THREE.Math-ish
41481
41482 do {
41483
41485
41486 if ( value !== undefined ) {
41487
41488 times.push( key.time );
41489 value.toArray( values, values.length );
41490
41491 }
41492
41493 key = jsonKeys[ i ++ ];
41494
41495 } while ( key !== undefined );
41496
41497 } else {
41498
41499 // otherwise push as-is
41500
41501 do {
41502
41504
41505 if ( value !== undefined ) {
41506
41507 times.push( key.time );
41508 values.push( value );
41509
41510 }
41511
41512 key = jsonKeys[ i ++ ];
41513
41514 } while ( key !== undefined );
41515
41516 }
41517
41518 }
41519
41520 function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {
41521
41522 const clip = sourceClip.clone();
41523
41524 clip.name = name;
41525
41526 const tracks = [];
41527
41528 for ( let i = 0; i < clip.tracks.length; ++ i ) {
41529
41530 const track = clip.tracks[ i ];
41531 const valueSize = track.getValueSize();
41532
41533 const times = [];
41534 const values = [];
41535
41536 for ( let j = 0; j < track.times.length; ++ j ) {
41537
41538 const frame = track.times[ j ] * fps;
41539
41540 if ( frame < startFrame || frame >= endFrame ) continue;
41541
41542 times.push( track.times[ j ] );
41543
41544 for ( let k = 0; k < valueSize; ++ k ) {
41545
41546 values.push( track.values[ j * valueSize + k ] );
41547
41548 }
41549
41550 }
41551
41552 if ( times.length === 0 ) continue;
41553
41554 track.times = convertArray( times, track.times.constructor );
41555 track.values = convertArray( values, track.values.constructor );
41556
41557 tracks.push( track );
41558
41559 }
41560
41561 clip.tracks = tracks;
41562
41563 // find minimum .times value across all tracks in the trimmed clip
41564
41566
41567 for ( let i = 0; i < clip.tracks.length; ++ i ) {
41568
41569 if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {
41570
41571 minStartTime = clip.tracks[ i ].times[ 0 ];
41572
41573 }
41574
41575 }
41576
41577 // shift all tracks such that clip begins at t=0
41578
41579 for ( let i = 0; i < clip.tracks.length; ++ i ) {
41580
41581 clip.tracks[ i ].shift( - 1 * minStartTime );
41582
41583 }
41584
41585 clip.resetDuration();
41586
41587 return clip;
41588
41589 }
41590
41592
41593 if ( fps <= 0 ) fps = 30;
41594
41595 const numTracks = referenceClip.tracks.length;
41597
41598 // Make each track's values relative to the values at the reference frame
41599 for ( let i = 0; i < numTracks; ++ i ) {
41600
41601 const referenceTrack = referenceClip.tracks[ i ];
41602 const referenceTrackType = referenceTrack.ValueTypeName;
41603
41604 // Skip this track if it's non-numeric
41605 if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;
41606
41607 // Find the track in the target clip whose name and type matches the reference track
41608 const targetTrack = targetClip.tracks.find( function ( track ) {
41609
41610 return track.name === referenceTrack.name
41611 && track.ValueTypeName === referenceTrackType;
41612
41613 } );
41614
41615 if ( targetTrack === undefined ) continue;
41616
41617 let referenceOffset = 0;
41618 const referenceValueSize = referenceTrack.getValueSize();
41619
41620 if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41621
41623
41624 }
41625
41626 let targetOffset = 0;
41627 const targetValueSize = targetTrack.getValueSize();
41628
41629 if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
41630
41632
41633 }
41634
41635 const lastIndex = referenceTrack.times.length - 1;
41637
41638 // Find the value to subtract out of the track
41639 if ( referenceTime <= referenceTrack.times[ 0 ] ) {
41640
41641 // Reference frame is earlier than the first keyframe, so just use the first keyframe
41645
41646 } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {
41647
41648 // Reference frame is after the last keyframe, so just use the last keyframe
41652
41653 } else {
41654
41655 // Interpolate to the reference value
41656 const interpolant = referenceTrack.createInterpolant();
41659 interpolant.evaluate( referenceTime );
41660 referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );
41661
41662 }
41663
41664 // Conjugate the quaternion
41665 if ( referenceTrackType === 'quaternion' ) {
41666
41667 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();
41668 referenceQuat.toArray( referenceValue );
41669
41670 }
41671
41672 // Subtract the reference value from all of the track values
41673
41674 const numTimes = targetTrack.times.length;
41675 for ( let j = 0; j < numTimes; ++ j ) {
41676
41678
41679 if ( referenceTrackType === 'quaternion' ) {
41680
41681 // Multiply the conjugate for quaternion track types
41682 Quaternion.multiplyQuaternionsFlat(
41683 targetTrack.values,
41684 valueStart,
41686 0,
41687 targetTrack.values,
41689 );
41690
41691 } else {
41692
41694
41695 // Subtract each value for all other numeric track types
41696 for ( let k = 0; k < valueEnd; ++ k ) {
41697
41698 targetTrack.values[ valueStart + k ] -= referenceValue[ k ];
41699
41700 }
41701
41702 }
41703
41704 }
41705
41706 }
41707
41709
41710 return targetClip;
41711
41712 }
41713
41714 const AnimationUtils = {
41722 };
41723
41745 class Interpolant {
41746
41748
41750 this._cachedIndex = 0;
41751
41753 resultBuffer : new sampleValues.constructor( sampleSize );
41755 this.valueSize = sampleSize;
41756
41757 this.settings = null;
41758 this.DefaultSettings_ = {};
41759
41760 }
41761
41762 evaluate( t ) {
41763
41764 const pp = this.parameterPositions;
41765 let i1 = this._cachedIndex,
41766 t1 = pp[ i1 ],
41767 t0 = pp[ i1 - 1 ];
41768
41770
41771 seek: {
41772
41773 let right;
41774
41775 linear_scan: {
41776
41777 //- See http://jsperf.com/comparison-to-undefined/3
41778 //- slower code:
41779 //-
41780 //- if ( t >= t1 || t1 === undefined ) {
41781 forward_scan: if ( ! ( t < t1 ) ) {
41782
41783 for ( let giveUpAt = i1 + 2; ; ) {
41784
41785 if ( t1 === undefined ) {
41786
41787 if ( t < t0 ) break forward_scan;
41788
41789 // after end
41790
41791 i1 = pp.length;
41792 this._cachedIndex = i1;
41793 return this.copySampleValue_( i1 - 1 );
41794
41795 }
41796
41797 if ( i1 === giveUpAt ) break; // this loop
41798
41799 t0 = t1;
41800 t1 = pp[ ++ i1 ];
41801
41802 if ( t < t1 ) {
41803
41804 // we have arrived at the sought interval
41805 break seek;
41806
41807 }
41808
41809 }
41810
41811 // prepare binary search on the right side of the index
41812 right = pp.length;
41813 break linear_scan;
41814
41815 }
41816
41817 //- slower code:
41818 //- if ( t < t0 || t0 === undefined ) {
41819 if ( ! ( t >= t0 ) ) {
41820
41821 // looping?
41822
41823 const t1global = pp[ 1 ];
41824
41825 if ( t < t1global ) {
41826
41827 i1 = 2; // + 1, using the scan for the details
41828 t0 = t1global;
41829
41830 }
41831
41832 // linear reverse scan
41833
41834 for ( let giveUpAt = i1 - 2; ; ) {
41835
41836 if ( t0 === undefined ) {
41837
41838 // before start
41839
41840 this._cachedIndex = 0;
41841 return this.copySampleValue_( 0 );
41842
41843 }
41844
41845 if ( i1 === giveUpAt ) break; // this loop
41846
41847 t1 = t0;
41848 t0 = pp[ -- i1 - 1 ];
41849
41850 if ( t >= t0 ) {
41851
41852 // we have arrived at the sought interval
41853 break seek;
41854
41855 }
41856
41857 }
41858
41859 // prepare binary search on the left side of the index
41860 right = i1;
41861 i1 = 0;
41862 break linear_scan;
41863
41864 }
41865
41866 // the interval is valid
41867
41868 break validate_interval;
41869
41870 } // linear scan
41871
41872 // binary search
41873
41874 while ( i1 < right ) {
41875
41876 const mid = ( i1 + right ) >>> 1;
41877
41878 if ( t < pp[ mid ] ) {
41879
41880 right = mid;
41881
41882 } else {
41883
41884 i1 = mid + 1;
41885
41886 }
41887
41888 }
41889
41890 t1 = pp[ i1 ];
41891 t0 = pp[ i1 - 1 ];
41892
41893 // check boundary cases, again
41894
41895 if ( t0 === undefined ) {
41896
41897 this._cachedIndex = 0;
41898 return this.copySampleValue_( 0 );
41899
41900 }
41901
41902 if ( t1 === undefined ) {
41903
41904 i1 = pp.length;
41905 this._cachedIndex = i1;
41906 return this.copySampleValue_( i1 - 1 );
41907
41908 }
41909
41910 } // seek
41911
41912 this._cachedIndex = i1;
41913
41914 this.intervalChanged_( i1, t0, t1 );
41915
41916 } // validate_interval
41917
41918 return this.interpolate_( i1, t0, t, t1 );
41919
41920 }
41921
41922 getSettings_() {
41923
41924 return this.settings || this.DefaultSettings_;
41925
41926 }
41927
41928 copySampleValue_( index ) {
41929
41930 // copies a sample value to the result buffer
41931
41932 const result = this.resultBuffer,
41933 values = this.sampleValues,
41934 stride = this.valueSize,
41935 offset = index * stride;
41936
41937 for ( let i = 0; i !== stride; ++ i ) {
41938
41939 result[ i ] = values[ offset + i ];
41940
41941 }
41942
41943 return result;
41944
41945 }
41946
41947 // Template methods for derived classes:
41948
41949 interpolate_( /* i1, t0, t, t1 */ ) {
41950
41951 throw new Error( 'call to abstract method' );
41952 // implementations shall return this.resultBuffer
41953
41954 }
41955
41956 intervalChanged_( /* i1, t0, t1 */ ) {
41957
41958 // empty
41959
41960 }
41961
41962 }
41963
41972 class CubicInterpolant extends Interpolant {
41973
41975
41977
41978 this._weightPrev = - 0;
41979 this._offsetPrev = - 0;
41980 this._weightNext = - 0;
41981 this._offsetNext = - 0;
41982
41983 this.DefaultSettings_ = {
41984
41987
41988 };
41989
41990 }
41991
41992 intervalChanged_( i1, t0, t1 ) {
41993
41994 const pp = this.parameterPositions;
41995 let iPrev = i1 - 2,
41996 iNext = i1 + 1,
41997
41998 tPrev = pp[ iPrev ],
41999 tNext = pp[ iNext ];
42000
42001 if ( tPrev === undefined ) {
42002
42003 switch ( this.getSettings_().endingStart ) {
42004
42005 case ZeroSlopeEnding:
42006
42007 // f'(t0) = 0
42008 iPrev = i1;
42009 tPrev = 2 * t0 - t1;
42010
42011 break;
42012
42013 case WrapAroundEnding:
42014
42015 // use the other end of the curve
42016 iPrev = pp.length - 2;
42017 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];
42018
42019 break;
42020
42021 default: // ZeroCurvatureEnding
42022
42023 // f''(t0) = 0 a.k.a. Natural Spline
42024 iPrev = i1;
42025 tPrev = t1;
42026
42027 }
42028
42029 }
42030
42031 if ( tNext === undefined ) {
42032
42033 switch ( this.getSettings_().endingEnd ) {
42034
42035 case ZeroSlopeEnding:
42036
42037 // f'(tN) = 0
42038 iNext = i1;
42039 tNext = 2 * t1 - t0;
42040
42041 break;
42042
42043 case WrapAroundEnding:
42044
42045 // use the other end of the curve
42046 iNext = 1;
42047 tNext = t1 + pp[ 1 ] - pp[ 0 ];
42048
42049 break;
42050
42051 default: // ZeroCurvatureEnding
42052
42053 // f''(tN) = 0, a.k.a. Natural Spline
42054 iNext = i1 - 1;
42055 tNext = t0;
42056
42057 }
42058
42059 }
42060
42061 const halfDt = ( t1 - t0 ) * 0.5,
42062 stride = this.valueSize;
42063
42064 this._weightPrev = halfDt / ( t0 - tPrev );
42065 this._weightNext = halfDt / ( tNext - t1 );
42066 this._offsetPrev = iPrev * stride;
42067 this._offsetNext = iNext * stride;
42068
42069 }
42070
42071 interpolate_( i1, t0, t, t1 ) {
42072
42073 const result = this.resultBuffer,
42074 values = this.sampleValues,
42075 stride = this.valueSize,
42076
42077 o1 = i1 * stride, o0 = o1 - stride,
42078 oP = this._offsetPrev, oN = this._offsetNext,
42079 wP = this._weightPrev, wN = this._weightNext,
42080
42081 p = ( t - t0 ) / ( t1 - t0 ),
42082 pp = p * p,
42083 ppp = pp * p;
42084
42085 // evaluate polynomials
42086
42087 const sP = - wP * ppp + 2 * wP * pp - wP * p;
42088 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;
42089 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
42090 const sN = wN * ppp - wN * pp;
42091
42092 // combine data linearly
42093
42094 for ( let i = 0; i !== stride; ++ i ) {
42095
42096 result[ i ] =
42097 sP * values[ oP + i ] +
42098 s0 * values[ o0 + i ] +
42099 s1 * values[ o1 + i ] +
42100 sN * values[ oN + i ];
42101
42102 }
42103
42104 return result;
42105
42106 }
42107
42108 }
42109
42110 class LinearInterpolant extends Interpolant {
42111
42113
42115
42116 }
42117
42118 interpolate_( i1, t0, t, t1 ) {
42119
42120 const result = this.resultBuffer,
42121 values = this.sampleValues,
42122 stride = this.valueSize,
42123
42124 offset1 = i1 * stride,
42126
42127 weight1 = ( t - t0 ) / ( t1 - t0 ),
42128 weight0 = 1 - weight1;
42129
42130 for ( let i = 0; i !== stride; ++ i ) {
42131
42132 result[ i ] =
42133 values[ offset0 + i ] * weight0 +
42134 values[ offset1 + i ] * weight1;
42135
42136 }
42137
42138 return result;
42139
42140 }
42141
42142 }
42143
42150 class DiscreteInterpolant extends Interpolant {
42151
42153
42155
42156 }
42157
42158 interpolate_( i1 /*, t0, t, t1 */ ) {
42159
42160 return this.copySampleValue_( i1 - 1 );
42161
42162 }
42163
42164 }
42165
42166 class KeyframeTrack {
42167
42169
42170 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );
42171 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );
42172
42173 this.name = name;
42174
42175 this.times = convertArray( times, this.TimeBufferType );
42176 this.values = convertArray( values, this.ValueBufferType );
42177
42179
42180 }
42181
42182 // Serialization (in static context, because of constructor invocation
42183 // and automatic invocation of .toJSON):
42184
42185 static toJSON( track ) {
42186
42187 const trackType = track.constructor;
42188
42189 let json;
42190
42191 // derived classes can define a static toJSON method
42192 if ( trackType.toJSON !== this.toJSON ) {
42193
42194 json = trackType.toJSON( track );
42195
42196 } else {
42197
42198 // by default, we assume the data can be serialized as-is
42199 json = {
42200
42201 'name': track.name,
42202 'times': convertArray( track.times, Array ),
42203 'values': convertArray( track.values, Array )
42204
42205 };
42206
42207 const interpolation = track.getInterpolation();
42208
42209 if ( interpolation !== track.DefaultInterpolation ) {
42210
42211 json.interpolation = interpolation;
42212
42213 }
42214
42215 }
42216
42217 json.type = track.ValueTypeName; // mandatory
42218
42219 return json;
42220
42221 }
42222
42224
42225 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );
42226
42227 }
42228
42230
42231 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result );
42232
42233 }
42234
42236
42237 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result );
42238
42239 }
42240
42242
42244
42245 switch ( interpolation ) {
42246
42248
42250
42251 break;
42252
42253 case InterpolateLinear:
42254
42255 factoryMethod = this.InterpolantFactoryMethodLinear;
42256
42257 break;
42258
42259 case InterpolateSmooth:
42260
42261 factoryMethod = this.InterpolantFactoryMethodSmooth;
42262
42263 break;
42264
42265 }
42266
42267 if ( factoryMethod === undefined ) {
42268
42269 const message = 'unsupported interpolation for ' +
42270 this.ValueTypeName + ' keyframe track named ' + this.name;
42271
42272 if ( this.createInterpolant === undefined ) {
42273
42274 // fall back to default, unless the default itself is messed up
42275 if ( interpolation !== this.DefaultInterpolation ) {
42276
42278
42279 } else {
42280
42281 throw new Error( message ); // fatal, in this case
42282
42283 }
42284
42285 }
42286
42287 console.warn( 'THREE.KeyframeTrack:', message );
42288 return this;
42289
42290 }
42291
42293
42294 return this;
42295
42296 }
42297
42299
42300 switch ( this.createInterpolant ) {
42301
42303
42304 return InterpolateDiscrete;
42305
42307
42308 return InterpolateLinear;
42309
42311
42312 return InterpolateSmooth;
42313
42314 }
42315
42316 }
42317
42318 getValueSize() {
42319
42320 return this.values.length / this.times.length;
42321
42322 }
42323
42324 // move all keyframes either forwards or backwards in time
42325 shift( timeOffset ) {
42326
42327 if ( timeOffset !== 0.0 ) {
42328
42329 const times = this.times;
42330
42331 for ( let i = 0, n = times.length; i !== n; ++ i ) {
42332
42333 times[ i ] += timeOffset;
42334
42335 }
42336
42337 }
42338
42339 return this;
42340
42341 }
42342
42343 // scale all keyframe times by a factor (useful for frame <-> seconds conversions)
42344 scale( timeScale ) {
42345
42346 if ( timeScale !== 1.0 ) {
42347
42348 const times = this.times;
42349
42350 for ( let i = 0, n = times.length; i !== n; ++ i ) {
42351
42352 times[ i ] *= timeScale;
42353
42354 }
42355
42356 }
42357
42358 return this;
42359
42360 }
42361
42362 // removes keyframes before and after animation without changing any values within the range [startTime, endTime].
42363 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
42364 trim( startTime, endTime ) {
42365
42366 const times = this.times,
42367 nKeys = times.length;
42368
42369 let from = 0,
42370 to = nKeys - 1;
42371
42372 while ( from !== nKeys && times[ from ] < startTime ) {
42373
42374 ++ from;
42375
42376 }
42377
42378 while ( to !== - 1 && times[ to ] > endTime ) {
42379
42380 -- to;
42381
42382 }
42383
42384 ++ to; // inclusive -> exclusive bound
42385
42386 if ( from !== 0 || to !== nKeys ) {
42387
42388 // empty tracks are forbidden, so keep at least one keyframe
42389 if ( from >= to ) {
42390
42391 to = Math.max( to, 1 );
42392 from = to - 1;
42393
42394 }
42395
42396 const stride = this.getValueSize();
42397 this.times = times.slice( from, to );
42398 this.values = this.values.slice( from * stride, to * stride );
42399
42400 }
42401
42402 return this;
42403
42404 }
42405
42406 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable
42407 validate() {
42408
42409 let valid = true;
42410
42411 const valueSize = this.getValueSize();
42412 if ( valueSize - Math.floor( valueSize ) !== 0 ) {
42413
42414 console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );
42415 valid = false;
42416
42417 }
42418
42419 const times = this.times,
42420 values = this.values,
42421
42422 nKeys = times.length;
42423
42424 if ( nKeys === 0 ) {
42425
42426 console.error( 'THREE.KeyframeTrack: Track is empty.', this );
42427 valid = false;
42428
42429 }
42430
42431 let prevTime = null;
42432
42433 for ( let i = 0; i !== nKeys; i ++ ) {
42434
42435 const currTime = times[ i ];
42436
42437 if ( typeof currTime === 'number' && isNaN( currTime ) ) {
42438
42439 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );
42440 valid = false;
42441 break;
42442
42443 }
42444
42445 if ( prevTime !== null && prevTime > currTime ) {
42446
42447 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );
42448 valid = false;
42449 break;
42450
42451 }
42452
42454
42455 }
42456
42457 if ( values !== undefined ) {
42458
42459 if ( isTypedArray( values ) ) {
42460
42461 for ( let i = 0, n = values.length; i !== n; ++ i ) {
42462
42463 const value = values[ i ];
42464
42465 if ( isNaN( value ) ) {
42466
42467 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );
42468 valid = false;
42469 break;
42470
42471 }
42472
42473 }
42474
42475 }
42476
42477 }
42478
42479 return valid;
42480
42481 }
42482
42483 // removes equivalent sequential keys as common in morph target sequences
42484 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0)
42485 optimize() {
42486
42487 // times or values may be shared with other tracks, so overwriting is unsafe
42488 const times = this.times.slice(),
42489 values = this.values.slice(),
42490 stride = this.getValueSize(),
42491
42493
42494 lastIndex = times.length - 1;
42495
42496 let writeIndex = 1;
42497
42498 for ( let i = 1; i < lastIndex; ++ i ) {
42499
42500 let keep = false;
42501
42502 const time = times[ i ];
42503 const timeNext = times[ i + 1 ];
42504
42505 // remove adjacent keyframes scheduled at the same time
42506
42507 if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {
42508
42509 if ( ! smoothInterpolation ) {
42510
42511 // remove unnecessary keyframes same as their neighbors
42512
42513 const offset = i * stride,
42514 offsetP = offset - stride,
42515 offsetN = offset + stride;
42516
42517 for ( let j = 0; j !== stride; ++ j ) {
42518
42519 const value = values[ offset + j ];
42520
42521 if ( value !== values[ offsetP + j ] ||
42522 value !== values[ offsetN + j ] ) {
42523
42524 keep = true;
42525 break;
42526
42527 }
42528
42529 }
42530
42531 } else {
42532
42533 keep = true;
42534
42535 }
42536
42537 }
42538
42539 // in-place compaction
42540
42541 if ( keep ) {
42542
42543 if ( i !== writeIndex ) {
42544
42545 times[ writeIndex ] = times[ i ];
42546
42547 const readOffset = i * stride,
42549
42550 for ( let j = 0; j !== stride; ++ j ) {
42551
42552 values[ writeOffset + j ] = values[ readOffset + j ];
42553
42554 }
42555
42556 }
42557
42558 ++ writeIndex;
42559
42560 }
42561
42562 }
42563
42564 // flush last keyframe (compaction looks ahead)
42565
42566 if ( lastIndex > 0 ) {
42567
42569
42570 for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {
42571
42572 values[ writeOffset + j ] = values[ readOffset + j ];
42573
42574 }
42575
42576 ++ writeIndex;
42577
42578 }
42579
42580 if ( writeIndex !== times.length ) {
42581
42582 this.times = times.slice( 0, writeIndex );
42583 this.values = values.slice( 0, writeIndex * stride );
42584
42585 } else {
42586
42587 this.times = times;
42588 this.values = values;
42589
42590 }
42591
42592 return this;
42593
42594 }
42595
42596 clone() {
42597
42598 const times = this.times.slice();
42599 const values = this.values.slice();
42600
42601 const TypedKeyframeTrack = this.constructor;
42602 const track = new TypedKeyframeTrack( this.name, times, values );
42603
42604 // Interpolant argument to constructor is not saved, so copy the factory method directly.
42605 track.createInterpolant = this.createInterpolant;
42606
42607 return track;
42608
42609 }
42610
42611 }
42612
42613 KeyframeTrack.prototype.TimeBufferType = Float32Array;
42614 KeyframeTrack.prototype.ValueBufferType = Float32Array;
42615 KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42616
42620 class BooleanKeyframeTrack extends KeyframeTrack {}
42621
42622 BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';
42623 BooleanKeyframeTrack.prototype.ValueBufferType = Array;
42624 BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42625 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42626 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42627
42631 class ColorKeyframeTrack extends KeyframeTrack {}
42632
42633 ColorKeyframeTrack.prototype.ValueTypeName = 'color';
42634
42638 class NumberKeyframeTrack extends KeyframeTrack {}
42639
42640 NumberKeyframeTrack.prototype.ValueTypeName = 'number';
42641
42647
42649
42651
42652 }
42653
42654 interpolate_( i1, t0, t, t1 ) {
42655
42656 const result = this.resultBuffer,
42657 values = this.sampleValues,
42658 stride = this.valueSize,
42659
42660 alpha = ( t - t0 ) / ( t1 - t0 );
42661
42662 let offset = i1 * stride;
42663
42664 for ( let end = offset + stride; offset !== end; offset += 4 ) {
42665
42666 Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );
42667
42668 }
42669
42670 return result;
42671
42672 }
42673
42674 }
42675
42680
42682
42683 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );
42684
42685 }
42686
42687 }
42688
42689 QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';
42690 // ValueBufferType is inherited
42691 QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
42692 QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42693
42697 class StringKeyframeTrack extends KeyframeTrack {}
42698
42699 StringKeyframeTrack.prototype.ValueTypeName = 'string';
42700 StringKeyframeTrack.prototype.ValueBufferType = Array;
42701 StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
42702 StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
42703 StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
42704
42708 class VectorKeyframeTrack extends KeyframeTrack {}
42709
42710 VectorKeyframeTrack.prototype.ValueTypeName = 'vector';
42711
42712 class AnimationClip {
42713
42715
42716 this.name = name;
42717 this.tracks = tracks;
42718 this.duration = duration;
42719 this.blendMode = blendMode;
42720
42721 this.uuid = generateUUID();
42722
42723 // this means it should figure out its duration by scanning the tracks
42724 if ( this.duration < 0 ) {
42725
42726 this.resetDuration();
42727
42728 }
42729
42730 }
42731
42732
42733 static parse( json ) {
42734
42735 const tracks = [],
42736 jsonTracks = json.tracks,
42737 frameTime = 1.0 / ( json.fps || 1.0 );
42738
42739 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {
42740
42741 tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
42742
42743 }
42744
42745 const clip = new this( json.name, json.duration, tracks, json.blendMode );
42746 clip.uuid = json.uuid;
42747
42748 return clip;
42749
42750 }
42751
42752 static toJSON( clip ) {
42753
42754 const tracks = [],
42755 clipTracks = clip.tracks;
42756
42757 const json = {
42758
42759 'name': clip.name,
42760 'duration': clip.duration,
42761 'tracks': tracks,
42762 'uuid': clip.uuid,
42763 'blendMode': clip.blendMode
42764
42765 };
42766
42767 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
42768
42769 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );
42770
42771 }
42772
42773 return json;
42774
42775 }
42776
42778
42779 const numMorphTargets = morphTargetSequence.length;
42780 const tracks = [];
42781
42782 for ( let i = 0; i < numMorphTargets; i ++ ) {
42783
42784 let times = [];
42785 let values = [];
42786
42787 times.push(
42788 ( i + numMorphTargets - 1 ) % numMorphTargets,
42789 i,
42790 ( i + 1 ) % numMorphTargets );
42791
42792 values.push( 0, 1, 0 );
42793
42794 const order = getKeyframeOrder( times );
42795 times = sortedArray( times, 1, order );
42796 values = sortedArray( values, 1, order );
42797
42798 // if there is a key at the first frame, duplicate it as the
42799 // last frame as well for perfect loop.
42800 if ( ! noLoop && times[ 0 ] === 0 ) {
42801
42802 times.push( numMorphTargets );
42803 values.push( values[ 0 ] );
42804
42805 }
42806
42807 tracks.push(
42809 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',
42810 times, values
42811 ).scale( 1.0 / fps ) );
42812
42813 }
42814
42815 return new this( name, - 1, tracks );
42816
42817 }
42818
42819 static findByName( objectOrClipArray, name ) {
42820
42822
42823 if ( ! Array.isArray( objectOrClipArray ) ) {
42824
42825 const o = objectOrClipArray;
42826 clipArray = o.geometry && o.geometry.animations || o.animations;
42827
42828 }
42829
42830 for ( let i = 0; i < clipArray.length; i ++ ) {
42831
42832 if ( clipArray[ i ].name === name ) {
42833
42834 return clipArray[ i ];
42835
42836 }
42837
42838 }
42839
42840 return null;
42841
42842 }
42843
42845
42846 const animationToMorphTargets = {};
42847
42848 // tested with https://regex101.com/ on trick sequences
42849 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059
42850 const pattern = /^([\w-]*?)([\d]+)$/;
42851
42852 // sort morph target names into animation groups based
42853 // patterns like Walk_001, Walk_002, Run_001, Run_002
42854 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) {
42855
42856 const morphTarget = morphTargets[ i ];
42857 const parts = morphTarget.name.match( pattern );
42858
42859 if ( parts && parts.length > 1 ) {
42860
42861 const name = parts[ 1 ];
42862
42864
42865 if ( ! animationMorphTargets ) {
42866
42868
42869 }
42870
42872
42873 }
42874
42875 }
42876
42877 const clips = [];
42878
42879 for ( const name in animationToMorphTargets ) {
42880
42882
42883 }
42884
42885 return clips;
42886
42887 }
42888
42889 // parse the animation.hierarchy format
42890 static parseAnimation( animation, bones ) {
42891
42892 if ( ! animation ) {
42893
42894 console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );
42895 return null;
42896
42897 }
42898
42900
42901 // only return track if there are actually keys.
42902 if ( animationKeys.length !== 0 ) {
42903
42904 const times = [];
42905 const values = [];
42906
42908
42909 // empty keys are filtered out, so check again
42910 if ( times.length !== 0 ) {
42911
42912 destTracks.push( new trackType( trackName, times, values ) );
42913
42914 }
42915
42916 }
42917
42918 };
42919
42920 const tracks = [];
42921
42922 const clipName = animation.name || 'default';
42923 const fps = animation.fps || 30;
42924 const blendMode = animation.blendMode;
42925
42926 // automatic length determination in AnimationClip.
42927 let duration = animation.length || - 1;
42928
42929 const hierarchyTracks = animation.hierarchy || [];
42930
42931 for ( let h = 0; h < hierarchyTracks.length; h ++ ) {
42932
42933 const animationKeys = hierarchyTracks[ h ].keys;
42934
42935 // skip empty tracks
42936 if ( ! animationKeys || animationKeys.length === 0 ) continue;
42937
42938 // process morph targets
42939 if ( animationKeys[ 0 ].morphTargets ) {
42940
42941 // figure out all morph targets used in this track
42942 const morphTargetNames = {};
42943
42944 let k;
42945
42946 for ( k = 0; k < animationKeys.length; k ++ ) {
42947
42948 if ( animationKeys[ k ].morphTargets ) {
42949
42950 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {
42951
42952 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;
42953
42954 }
42955
42956 }
42957
42958 }
42959
42960 // create a track for each morph target with all zero
42961 // morphTargetInfluences except for the keys in which
42962 // the morphTarget is named.
42963 for ( const morphTargetName in morphTargetNames ) {
42964
42965 const times = [];
42966 const values = [];
42967
42968 for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {
42969
42970 const animationKey = animationKeys[ k ];
42971
42972 times.push( animationKey.time );
42973 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );
42974
42975 }
42976
42977 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );
42978
42979 }
42980
42981 duration = morphTargetNames.length * fps;
42982
42983 } else {
42984
42985 // ...assume skeletal animation
42986
42987 const boneName = '.bones[' + bones[ h ].name + ']';
42988
42990 VectorKeyframeTrack, boneName + '.position',
42991 animationKeys, 'pos', tracks );
42992
42994 QuaternionKeyframeTrack, boneName + '.quaternion',
42995 animationKeys, 'rot', tracks );
42996
42998 VectorKeyframeTrack, boneName + '.scale',
42999 animationKeys, 'scl', tracks );
43000
43001 }
43002
43003 }
43004
43005 if ( tracks.length === 0 ) {
43006
43007 return null;
43008
43009 }
43010
43011 const clip = new this( clipName, duration, tracks, blendMode );
43012
43013 return clip;
43014
43015 }
43016
43017 resetDuration() {
43018
43019 const tracks = this.tracks;
43020 let duration = 0;
43021
43022 for ( let i = 0, n = tracks.length; i !== n; ++ i ) {
43023
43024 const track = this.tracks[ i ];
43025
43026 duration = Math.max( duration, track.times[ track.times.length - 1 ] );
43027
43028 }
43029
43030 this.duration = duration;
43031
43032 return this;
43033
43034 }
43035
43036 trim() {
43037
43038 for ( let i = 0; i < this.tracks.length; i ++ ) {
43039
43040 this.tracks[ i ].trim( 0, this.duration );
43041
43042 }
43043
43044 return this;
43045
43046 }
43047
43048 validate() {
43049
43050 let valid = true;
43051
43052 for ( let i = 0; i < this.tracks.length; i ++ ) {
43053
43054 valid = valid && this.tracks[ i ].validate();
43055
43056 }
43057
43058 return valid;
43059
43060 }
43061
43062 optimize() {
43063
43064 for ( let i = 0; i < this.tracks.length; i ++ ) {
43065
43066 this.tracks[ i ].optimize();
43067
43068 }
43069
43070 return this;
43071
43072 }
43073
43074 clone() {
43075
43076 const tracks = [];
43077
43078 for ( let i = 0; i < this.tracks.length; i ++ ) {
43079
43080 tracks.push( this.tracks[ i ].clone() );
43081
43082 }
43083
43084 return new this.constructor( this.name, this.duration, tracks, this.blendMode );
43085
43086 }
43087
43088 toJSON() {
43089
43090 return this.constructor.toJSON( this );
43091
43092 }
43093
43094 }
43095
43097
43098 switch ( typeName.toLowerCase() ) {
43099
43100 case 'scalar':
43101 case 'double':
43102 case 'float':
43103 case 'number':
43104 case 'integer':
43105
43106 return NumberKeyframeTrack;
43107
43108 case 'vector':
43109 case 'vector2':
43110 case 'vector3':
43111 case 'vector4':
43112
43113 return VectorKeyframeTrack;
43114
43115 case 'color':
43116
43117 return ColorKeyframeTrack;
43118
43119 case 'quaternion':
43120
43122
43123 case 'bool':
43124 case 'boolean':
43125
43126 return BooleanKeyframeTrack;
43127
43128 case 'string':
43129
43130 return StringKeyframeTrack;
43131
43132 }
43133
43134 throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );
43135
43136 }
43137
43138 function parseKeyframeTrack( json ) {
43139
43140 if ( json.type === undefined ) {
43141
43142 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );
43143
43144 }
43145
43147
43148 if ( json.times === undefined ) {
43149
43150 const times = [], values = [];
43151
43152 flattenJSON( json.keys, times, values, 'value' );
43153
43154 json.times = times;
43155 json.values = values;
43156
43157 }
43158
43159 // derived classes can define a static parse method
43160 if ( trackType.parse !== undefined ) {
43161
43162 return trackType.parse( json );
43163
43164 } else {
43165
43166 // by default, we assume a constructor compatible with the base
43167 return new trackType( json.name, json.times, json.values, json.interpolation );
43168
43169 }
43170
43171 }
43172
43173 const Cache = {
43174
43175 enabled: false,
43176
43177 files: {},
43178
43179 add: function ( key, file ) {
43180
43181 if ( this.enabled === false ) return;
43182
43183 // console.log( 'THREE.Cache', 'Adding key:', key );
43184
43185 this.files[ key ] = file;
43186
43187 },
43188
43189 get: function ( key ) {
43190
43191 if ( this.enabled === false ) return;
43192
43193 // console.log( 'THREE.Cache', 'Checking key:', key );
43194
43195 return this.files[ key ];
43196
43197 },
43198
43199 remove: function ( key ) {
43200
43201 delete this.files[ key ];
43202
43203 },
43204
43205 clear: function () {
43206
43207 this.files = {};
43208
43209 }
43210
43211 };
43212
43213 class LoadingManager {
43214
43216
43217 const scope = this;
43218
43219 let isLoading = false;
43220 let itemsLoaded = 0;
43221 let itemsTotal = 0;
43223 const handlers = [];
43224
43225 // Refer to #5689 for the reason why we don't set .onStart
43226 // in the constructor
43227
43228 this.onStart = undefined;
43229 this.onLoad = onLoad;
43230 this.onProgress = onProgress;
43231 this.onError = onError;
43232
43233 this.itemStart = function ( url ) {
43234
43235 itemsTotal ++;
43236
43237 if ( isLoading === false ) {
43238
43239 if ( scope.onStart !== undefined ) {
43240
43241 scope.onStart( url, itemsLoaded, itemsTotal );
43242
43243 }
43244
43245 }
43246
43247 isLoading = true;
43248
43249 };
43250
43251 this.itemEnd = function ( url ) {
43252
43253 itemsLoaded ++;
43254
43255 if ( scope.onProgress !== undefined ) {
43256
43257 scope.onProgress( url, itemsLoaded, itemsTotal );
43258
43259 }
43260
43261 if ( itemsLoaded === itemsTotal ) {
43262
43263 isLoading = false;
43264
43265 if ( scope.onLoad !== undefined ) {
43266
43267 scope.onLoad();
43268
43269 }
43270
43271 }
43272
43273 };
43274
43275 this.itemError = function ( url ) {
43276
43277 if ( scope.onError !== undefined ) {
43278
43279 scope.onError( url );
43280
43281 }
43282
43283 };
43284
43285 this.resolveURL = function ( url ) {
43286
43287 if ( urlModifier ) {
43288
43289 return urlModifier( url );
43290
43291 }
43292
43293 return url;
43294
43295 };
43296
43297 this.setURLModifier = function ( transform ) {
43298
43299 urlModifier = transform;
43300
43301 return this;
43302
43303 };
43304
43305 this.addHandler = function ( regex, loader ) {
43306
43307 handlers.push( regex, loader );
43308
43309 return this;
43310
43311 };
43312
43313 this.removeHandler = function ( regex ) {
43314
43315 const index = handlers.indexOf( regex );
43316
43317 if ( index !== - 1 ) {
43318
43319 handlers.splice( index, 2 );
43320
43321 }
43322
43323 return this;
43324
43325 };
43326
43327 this.getHandler = function ( file ) {
43328
43329 for ( let i = 0, l = handlers.length; i < l; i += 2 ) {
43330
43331 const regex = handlers[ i ];
43332 const loader = handlers[ i + 1 ];
43333
43334 if ( regex.global ) regex.lastIndex = 0; // see #17920
43335
43336 if ( regex.test( file ) ) {
43337
43338 return loader;
43339
43340 }
43341
43342 }
43343
43344 return null;
43345
43346 };
43347
43348 }
43349
43350 }
43351
43352 const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();
43353
43354 class Loader {
43355
43356 constructor( manager ) {
43357
43359
43360 this.crossOrigin = 'anonymous';
43361 this.withCredentials = false;
43362 this.path = '';
43363 this.resourcePath = '';
43364 this.requestHeader = {};
43365
43366 }
43367
43368 load( /* url, onLoad, onProgress, onError */ ) {}
43369
43370 loadAsync( url, onProgress ) {
43371
43372 const scope = this;
43373
43374 return new Promise( function ( resolve, reject ) {
43375
43376 scope.load( url, resolve, onProgress, reject );
43377
43378 } );
43379
43380 }
43381
43382 parse( /* data */ ) {}
43383
43385
43386 this.crossOrigin = crossOrigin;
43387 return this;
43388
43389 }
43390
43391 setWithCredentials( value ) {
43392
43393 this.withCredentials = value;
43394 return this;
43395
43396 }
43397
43398 setPath( path ) {
43399
43400 this.path = path;
43401 return this;
43402
43403 }
43404
43406
43408 return this;
43409
43410 }
43411
43413
43415 return this;
43416
43417 }
43418
43419 }
43420
43421 Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
43422
43423 const loading = {};
43424
43425 class HttpError extends Error {
43426
43428
43429 super( message );
43430 this.response = response;
43431
43432 }
43433
43434 }
43435
43436 class FileLoader extends Loader {
43437
43438 constructor( manager ) {
43439
43440 super( manager );
43441
43442 }
43443
43444 load( url, onLoad, onProgress, onError ) {
43445
43446 if ( url === undefined ) url = '';
43447
43448 if ( this.path !== undefined ) url = this.path + url;
43449
43450 url = this.manager.resolveURL( url );
43451
43452 const cached = Cache.get( url );
43453
43454 if ( cached !== undefined ) {
43455
43456 this.manager.itemStart( url );
43457
43458 setTimeout( () => {
43459
43460 if ( onLoad ) onLoad( cached );
43461
43462 this.manager.itemEnd( url );
43463
43464 }, 0 );
43465
43466 return cached;
43467
43468 }
43469
43470 // Check if request is duplicate
43471
43472 if ( loading[ url ] !== undefined ) {
43473
43474 loading[ url ].push( {
43475
43476 onLoad: onLoad,
43479
43480 } );
43481
43482 return;
43483
43484 }
43485
43486 // Initialise array for duplicate requests
43487 loading[ url ] = [];
43488
43489 loading[ url ].push( {
43490 onLoad: onLoad,
43493 } );
43494
43495 // create request
43496 const req = new Request( url, {
43497 headers: new Headers( this.requestHeader ),
43498 credentials: this.withCredentials ? 'include' : 'same-origin',
43499 // An abort controller could be added within a future PR
43500 } );
43501
43502 // record states ( avoid data race )
43503 const mimeType = this.mimeType;
43504 const responseType = this.responseType;
43505
43506 // start the fetch
43507 fetch( req )
43508 .then( response => {
43509
43510 if ( response.status === 200 || response.status === 0 ) {
43511
43512 // Some browsers return HTTP Status 0 when using non-http protocol
43513 // e.g. 'file://' or 'data://'. Handle as success.
43514
43515 if ( response.status === 0 ) {
43516
43517 console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
43518
43519 }
43520
43521 // Workaround: Checking if response.body === undefined for Alipay browser #23548
43522
43523 if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) {
43524
43525 return response;
43526
43527 }
43528
43529 const callbacks = loading[ url ];
43530 const reader = response.body.getReader();
43531
43532 // Nginx needs X-File-Size check
43533 // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content
43534 const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' );
43535 const total = contentLength ? parseInt( contentLength ) : 0;
43536 const lengthComputable = total !== 0;
43537 let loaded = 0;
43538
43539 // periodically read data into the new stream tracking while download progress
43540 const stream = new ReadableStream( {
43541 start( controller ) {
43542
43543 readData();
43544
43545 function readData() {
43546
43547 reader.read().then( ( { done, value } ) => {
43548
43549 if ( done ) {
43550
43551 controller.close();
43552
43553 } else {
43554
43555 loaded += value.byteLength;
43556
43557 const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );
43558 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43559
43560 const callback = callbacks[ i ];
43561 if ( callback.onProgress ) callback.onProgress( event );
43562
43563 }
43564
43565 controller.enqueue( value );
43566 readData();
43567
43568 }
43569
43570 } );
43571
43572 }
43573
43574 }
43575
43576 } );
43577
43578 return new Response( stream );
43579
43580 } else {
43581
43582 throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response );
43583
43584 }
43585
43586 } )
43587 .then( response => {
43588
43589 switch ( responseType ) {
43590
43591 case 'arraybuffer':
43592
43593 return response.arrayBuffer();
43594
43595 case 'blob':
43596
43597 return response.blob();
43598
43599 case 'document':
43600
43601 return response.text()
43602 .then( text => {
43603
43604 const parser = new DOMParser();
43605 return parser.parseFromString( text, mimeType );
43606
43607 } );
43608
43609 case 'json':
43610
43611 return response.json();
43612
43613 default:
43614
43615 if ( mimeType === undefined ) {
43616
43617 return response.text();
43618
43619 } else {
43620
43621 // sniff encoding
43622 const re = /charset="?([^;"\s]*)"?/i;
43623 const exec = re.exec( mimeType );
43624 const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined;
43625 const decoder = new TextDecoder( label );
43626 return response.arrayBuffer().then( ab => decoder.decode( ab ) );
43627
43628 }
43629
43630 }
43631
43632 } )
43633 .then( data => {
43634
43635 // Add to cache only on HTTP success, so that we do not cache
43636 // error response bodies as proper responses to requests.
43637 Cache.add( url, data );
43638
43639 const callbacks = loading[ url ];
43640 delete loading[ url ];
43641
43642 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43643
43644 const callback = callbacks[ i ];
43645 if ( callback.onLoad ) callback.onLoad( data );
43646
43647 }
43648
43649 } )
43650 .catch( err => {
43651
43652 // Abort errors and other errors are handled the same
43653
43654 const callbacks = loading[ url ];
43655
43656 if ( callbacks === undefined ) {
43657
43658 // When onLoad was called and url was deleted in `loading`
43659 this.manager.itemError( url );
43660 throw err;
43661
43662 }
43663
43664 delete loading[ url ];
43665
43666 for ( let i = 0, il = callbacks.length; i < il; i ++ ) {
43667
43668 const callback = callbacks[ i ];
43669 if ( callback.onError ) callback.onError( err );
43670
43671 }
43672
43673 this.manager.itemError( url );
43674
43675 } )
43676 .finally( () => {
43677
43678 this.manager.itemEnd( url );
43679
43680 } );
43681
43682 this.manager.itemStart( url );
43683
43684 }
43685
43686 setResponseType( value ) {
43687
43688 this.responseType = value;
43689 return this;
43690
43691 }
43692
43693 setMimeType( value ) {
43694
43695 this.mimeType = value;
43696 return this;
43697
43698 }
43699
43700 }
43701
43702 class AnimationLoader extends Loader {
43703
43704 constructor( manager ) {
43705
43706 super( manager );
43707
43708 }
43709
43710 load( url, onLoad, onProgress, onError ) {
43711
43712 const scope = this;
43713
43714 const loader = new FileLoader( this.manager );
43715 loader.setPath( this.path );
43716 loader.setRequestHeader( this.requestHeader );
43717 loader.setWithCredentials( this.withCredentials );
43718 loader.load( url, function ( text ) {
43719
43720 try {
43721
43722 onLoad( scope.parse( JSON.parse( text ) ) );
43723
43724 } catch ( e ) {
43725
43726 if ( onError ) {
43727
43728 onError( e );
43729
43730 } else {
43731
43732 console.error( e );
43733
43734 }
43735
43736 scope.manager.itemError( url );
43737
43738 }
43739
43740 }, onProgress, onError );
43741
43742 }
43743
43744 parse( json ) {
43745
43746 const animations = [];
43747
43748 for ( let i = 0; i < json.length; i ++ ) {
43749
43750 const clip = AnimationClip.parse( json[ i ] );
43751
43752 animations.push( clip );
43753
43754 }
43755
43756 return animations;
43757
43758 }
43759
43760 }
43761
43768 class CompressedTextureLoader extends Loader {
43769
43770 constructor( manager ) {
43771
43772 super( manager );
43773
43774 }
43775
43776 load( url, onLoad, onProgress, onError ) {
43777
43778 const scope = this;
43779
43780 const images = [];
43781
43782 const texture = new CompressedTexture();
43783
43784 const loader = new FileLoader( this.manager );
43785 loader.setPath( this.path );
43786 loader.setResponseType( 'arraybuffer' );
43787 loader.setRequestHeader( this.requestHeader );
43788 loader.setWithCredentials( scope.withCredentials );
43789
43790 let loaded = 0;
43791
43792 function loadTexture( i ) {
43793
43794 loader.load( url[ i ], function ( buffer ) {
43795
43796 const texDatas = scope.parse( buffer, true );
43797
43798 images[ i ] = {
43799 width: texDatas.width,
43800 height: texDatas.height,
43801 format: texDatas.format,
43802 mipmaps: texDatas.mipmaps
43803 };
43804
43805 loaded += 1;
43806
43807 if ( loaded === 6 ) {
43808
43809 if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;
43810
43811 texture.image = images;
43812 texture.format = texDatas.format;
43813 texture.needsUpdate = true;
43814
43815 if ( onLoad ) onLoad( texture );
43816
43817 }
43818
43819 }, onProgress, onError );
43820
43821 }
43822
43823 if ( Array.isArray( url ) ) {
43824
43825 for ( let i = 0, il = url.length; i < il; ++ i ) {
43826
43827 loadTexture( i );
43828
43829 }
43830
43831 } else {
43832
43833 // compressed cubemap texture stored in a single DDS file
43834
43835 loader.load( url, function ( buffer ) {
43836
43837 const texDatas = scope.parse( buffer, true );
43838
43839 if ( texDatas.isCubemap ) {
43840
43841 const faces = texDatas.mipmaps.length / texDatas.mipmapCount;
43842
43843 for ( let f = 0; f < faces; f ++ ) {
43844
43845 images[ f ] = { mipmaps: [] };
43846
43847 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) {
43848
43849 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
43850 images[ f ].format = texDatas.format;
43851 images[ f ].width = texDatas.width;
43852 images[ f ].height = texDatas.height;
43853
43854 }
43855
43856 }
43857
43858 texture.image = images;
43859
43860 } else {
43861
43862 texture.image.width = texDatas.width;
43863 texture.image.height = texDatas.height;
43864 texture.mipmaps = texDatas.mipmaps;
43865
43866 }
43867
43868 if ( texDatas.mipmapCount === 1 ) {
43869
43870 texture.minFilter = LinearFilter;
43871
43872 }
43873
43874 texture.format = texDatas.format;
43875 texture.needsUpdate = true;
43876
43877 if ( onLoad ) onLoad( texture );
43878
43879 }, onProgress, onError );
43880
43881 }
43882
43883 return texture;
43884
43885 }
43886
43887 }
43888
43889 class ImageLoader extends Loader {
43890
43891 constructor( manager ) {
43892
43893 super( manager );
43894
43895 }
43896
43897 load( url, onLoad, onProgress, onError ) {
43898
43899 if ( this.path !== undefined ) url = this.path + url;
43900
43901 url = this.manager.resolveURL( url );
43902
43903 const scope = this;
43904
43905 const cached = Cache.get( url );
43906
43907 if ( cached !== undefined ) {
43908
43909 scope.manager.itemStart( url );
43910
43911 setTimeout( function () {
43912
43913 if ( onLoad ) onLoad( cached );
43914
43915 scope.manager.itemEnd( url );
43916
43917 }, 0 );
43918
43919 return cached;
43920
43921 }
43922
43923 const image = createElementNS( 'img' );
43924
43925 function onImageLoad() {
43926
43927 removeEventListeners();
43928
43929 Cache.add( url, this );
43930
43931 if ( onLoad ) onLoad( this );
43932
43933 scope.manager.itemEnd( url );
43934
43935 }
43936
43937 function onImageError( event ) {
43938
43939 removeEventListeners();
43940
43941 if ( onError ) onError( event );
43942
43943 scope.manager.itemError( url );
43944 scope.manager.itemEnd( url );
43945
43946 }
43947
43948 function removeEventListeners() {
43949
43950 image.removeEventListener( 'load', onImageLoad, false );
43951 image.removeEventListener( 'error', onImageError, false );
43952
43953 }
43954
43955 image.addEventListener( 'load', onImageLoad, false );
43956 image.addEventListener( 'error', onImageError, false );
43957
43958 if ( url.slice( 0, 5 ) !== 'data:' ) {
43959
43960 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
43961
43962 }
43963
43964 scope.manager.itemStart( url );
43965
43966 image.src = url;
43967
43968 return image;
43969
43970 }
43971
43972 }
43973
43974 class CubeTextureLoader extends Loader {
43975
43976 constructor( manager ) {
43977
43978 super( manager );
43979
43980 }
43981
43982 load( urls, onLoad, onProgress, onError ) {
43983
43984 const texture = new CubeTexture();
43985 texture.colorSpace = SRGBColorSpace;
43986
43987 const loader = new ImageLoader( this.manager );
43988 loader.setCrossOrigin( this.crossOrigin );
43989 loader.setPath( this.path );
43990
43991 let loaded = 0;
43992
43993 function loadTexture( i ) {
43994
43995 loader.load( urls[ i ], function ( image ) {
43996
43997 texture.images[ i ] = image;
43998
43999 loaded ++;
44000
44001 if ( loaded === 6 ) {
44002
44003 texture.needsUpdate = true;
44004
44005 if ( onLoad ) onLoad( texture );
44006
44007 }
44008
44009 }, undefined, onError );
44010
44011 }
44012
44013 for ( let i = 0; i < urls.length; ++ i ) {
44014
44015 loadTexture( i );
44016
44017 }
44018
44019 return texture;
44020
44021 }
44022
44023 }
44024
44031 class DataTextureLoader extends Loader {
44032
44033 constructor( manager ) {
44034
44035 super( manager );
44036
44037 }
44038
44039 load( url, onLoad, onProgress, onError ) {
44040
44041 const scope = this;
44042
44043 const texture = new DataTexture();
44044
44045 const loader = new FileLoader( this.manager );
44046 loader.setResponseType( 'arraybuffer' );
44047 loader.setRequestHeader( this.requestHeader );
44048 loader.setPath( this.path );
44049 loader.setWithCredentials( scope.withCredentials );
44050 loader.load( url, function ( buffer ) {
44051
44052 let texData;
44053
44054 try {
44055
44056 texData = scope.parse( buffer );
44057
44058 } catch ( error ) {
44059
44060 if ( onError !== undefined ) {
44061
44062 onError( error );
44063
44064 } else {
44065
44066 console.error( error );
44067 return;
44068
44069 }
44070
44071 }
44072
44073 if ( texData.image !== undefined ) {
44074
44075 texture.image = texData.image;
44076
44077 } else if ( texData.data !== undefined ) {
44078
44079 texture.image.width = texData.width;
44080 texture.image.height = texData.height;
44081 texture.image.data = texData.data;
44082
44083 }
44084
44085 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;
44086 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;
44087
44088 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;
44089 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;
44090
44091 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;
44092
44093 if ( texData.colorSpace !== undefined ) {
44094
44095 texture.colorSpace = texData.colorSpace;
44096
44097 } else if ( texData.encoding !== undefined ) { // @deprecated, r152
44098
44099 texture.encoding = texData.encoding;
44100
44101 }
44102
44103 if ( texData.flipY !== undefined ) {
44104
44105 texture.flipY = texData.flipY;
44106
44107 }
44108
44109 if ( texData.format !== undefined ) {
44110
44111 texture.format = texData.format;
44112
44113 }
44114
44115 if ( texData.type !== undefined ) {
44116
44117 texture.type = texData.type;
44118
44119 }
44120
44121 if ( texData.mipmaps !== undefined ) {
44122
44123 texture.mipmaps = texData.mipmaps;
44124 texture.minFilter = LinearMipmapLinearFilter; // presumably...
44125
44126 }
44127
44128 if ( texData.mipmapCount === 1 ) {
44129
44130 texture.minFilter = LinearFilter;
44131
44132 }
44133
44134 if ( texData.generateMipmaps !== undefined ) {
44135
44136 texture.generateMipmaps = texData.generateMipmaps;
44137
44138 }
44139
44140 texture.needsUpdate = true;
44141
44142 if ( onLoad ) onLoad( texture, texData );
44143
44144 }, onProgress, onError );
44145
44146
44147 return texture;
44148
44149 }
44150
44151 }
44152
44153 class TextureLoader extends Loader {
44154
44155 constructor( manager ) {
44156
44157 super( manager );
44158
44159 }
44160
44161 load( url, onLoad, onProgress, onError ) {
44162
44163 const texture = new Texture();
44164
44165 const loader = new ImageLoader( this.manager );
44166 loader.setCrossOrigin( this.crossOrigin );
44167 loader.setPath( this.path );
44168
44169 loader.load( url, function ( image ) {
44170
44171 texture.image = image;
44172 texture.needsUpdate = true;
44173
44174 if ( onLoad !== undefined ) {
44175
44176 onLoad( texture );
44177
44178 }
44179
44180 }, onProgress, onError );
44181
44182 return texture;
44183
44184 }
44185
44186 }
44187
44188 class Light extends Object3D {
44189
44190 constructor( color, intensity = 1 ) {
44191
44192 super();
44193
44194 this.isLight = true;
44195
44196 this.type = 'Light';
44197
44198 this.color = new Color( color );
44199 this.intensity = intensity;
44200
44201 }
44202
44203 dispose() {
44204
44205 // Empty here in base class; some subclasses override.
44206
44207 }
44208
44209 copy( source, recursive ) {
44210
44211 super.copy( source, recursive );
44212
44213 this.color.copy( source.color );
44214 this.intensity = source.intensity;
44215
44216 return this;
44217
44218 }
44219
44220 toJSON( meta ) {
44221
44222 const data = super.toJSON( meta );
44223
44224 data.object.color = this.color.getHex();
44225 data.object.intensity = this.intensity;
44226
44227 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();
44228
44229 if ( this.distance !== undefined ) data.object.distance = this.distance;
44230 if ( this.angle !== undefined ) data.object.angle = this.angle;
44231 if ( this.decay !== undefined ) data.object.decay = this.decay;
44232 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;
44233
44234 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();
44235
44236 return data;
44237
44238 }
44239
44240 }
44241
44242 class HemisphereLight extends Light {
44243
44244 constructor( skyColor, groundColor, intensity ) {
44245
44246 super( skyColor, intensity );
44247
44248 this.isHemisphereLight = true;
44249
44250 this.type = 'HemisphereLight';
44251
44252 this.position.copy( Object3D.DEFAULT_UP );
44253 this.updateMatrix();
44254
44255 this.groundColor = new Color( groundColor );
44256
44257 }
44258
44259 copy( source, recursive ) {
44260
44261 super.copy( source, recursive );
44262
44263 this.groundColor.copy( source.groundColor );
44264
44265 return this;
44266
44267 }
44268
44269 }
44270
44271 const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();
44272 const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();
44273 const _lookTarget$1 = /*@__PURE__*/ new Vector3();
44274
44275 class LightShadow {
44276
44277 constructor( camera ) {
44278
44279 this.camera = camera;
44280
44281 this.bias = 0;
44282 this.normalBias = 0;
44283 this.radius = 1;
44284 this.blurSamples = 8;
44285
44286 this.mapSize = new Vector2( 512, 512 );
44287
44288 this.map = null;
44289 this.mapPass = null;
44290 this.matrix = new Matrix4();
44291
44292 this.autoUpdate = true;
44293 this.needsUpdate = false;
44294
44295 this._frustum = new Frustum();
44296 this._frameExtents = new Vector2( 1, 1 );
44297
44298 this._viewportCount = 1;
44299
44300 this._viewports = [
44301
44302 new Vector4( 0, 0, 1, 1 )
44303
44304 ];
44305
44306 }
44307
44308 getViewportCount() {
44309
44310 return this._viewportCount;
44311
44312 }
44313
44314 getFrustum() {
44315
44316 return this._frustum;
44317
44318 }
44319
44320 updateMatrices( light ) {
44321
44322 const shadowCamera = this.camera;
44323 const shadowMatrix = this.matrix;
44324
44325 _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );
44326 shadowCamera.position.copy( _lightPositionWorld$1 );
44327
44328 _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );
44329 shadowCamera.lookAt( _lookTarget$1 );
44330 shadowCamera.updateMatrixWorld();
44331
44332 _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
44333 this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );
44334
44335 shadowMatrix.set(
44336 0.5, 0.0, 0.0, 0.5,
44337 0.0, 0.5, 0.0, 0.5,
44338 0.0, 0.0, 0.5, 0.5,
44339 0.0, 0.0, 0.0, 1.0
44340 );
44341
44342 shadowMatrix.multiply( _projScreenMatrix$1 );
44343
44344 }
44345
44346 getViewport( viewportIndex ) {
44347
44348 return this._viewports[ viewportIndex ];
44349
44350 }
44351
44352 getFrameExtents() {
44353
44354 return this._frameExtents;
44355
44356 }
44357
44358 dispose() {
44359
44360 if ( this.map ) {
44361
44362 this.map.dispose();
44363
44364 }
44365
44366 if ( this.mapPass ) {
44367
44368 this.mapPass.dispose();
44369
44370 }
44371
44372 }
44373
44374 copy( source ) {
44375
44376 this.camera = source.camera.clone();
44377
44378 this.bias = source.bias;
44379 this.radius = source.radius;
44380
44381 this.mapSize.copy( source.mapSize );
44382
44383 return this;
44384
44385 }
44386
44387 clone() {
44388
44389 return new this.constructor().copy( this );
44390
44391 }
44392
44393 toJSON() {
44394
44395 const object = {};
44396
44397 if ( this.bias !== 0 ) object.bias = this.bias;
44398 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias;
44399 if ( this.radius !== 1 ) object.radius = this.radius;
44400 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();
44401
44402 object.camera = this.camera.toJSON( false ).object;
44403 delete object.camera.matrix;
44404
44405 return object;
44406
44407 }
44408
44409 }
44410
44411 class SpotLightShadow extends LightShadow {
44412
44413 constructor() {
44414
44415 super( new PerspectiveCamera( 50, 1, 0.5, 500 ) );
44416
44417 this.isSpotLightShadow = true;
44418
44419 this.focus = 1;
44420
44421 }
44422
44423 updateMatrices( light ) {
44424
44425 const camera = this.camera;
44426
44427 const fov = RAD2DEG * 2 * light.angle * this.focus;
44428 const aspect = this.mapSize.width / this.mapSize.height;
44429 const far = light.distance || camera.far;
44430
44431 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {
44432
44433 camera.fov = fov;
44434 camera.aspect = aspect;
44435 camera.far = far;
44436 camera.updateProjectionMatrix();
44437
44438 }
44439
44440 super.updateMatrices( light );
44441
44442 }
44443
44444 copy( source ) {
44445
44446 super.copy( source );
44447
44448 this.focus = source.focus;
44449
44450 return this;
44451
44452 }
44453
44454 }
44455
44456 class SpotLight extends Light {
44457
44458 constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) {
44459
44460 super( color, intensity );
44461
44462 this.isSpotLight = true;
44463
44464 this.type = 'SpotLight';
44465
44466 this.position.copy( Object3D.DEFAULT_UP );
44467 this.updateMatrix();
44468
44469 this.target = new Object3D();
44470
44471 this.distance = distance;
44472 this.angle = angle;
44473 this.penumbra = penumbra;
44474 this.decay = decay;
44475
44476 this.map = null;
44477
44478 this.shadow = new SpotLightShadow();
44479
44480 }
44481
44482 get power() {
44483
44484 // compute the light's luminous power (in lumens) from its intensity (in candela)
44485 // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)
44486 return this.intensity * Math.PI;
44487
44488 }
44489
44490 set power( power ) {
44491
44492 // set the light's intensity (in candela) from the desired luminous power (in lumens)
44493 this.intensity = power / Math.PI;
44494
44495 }
44496
44497 dispose() {
44498
44499 this.shadow.dispose();
44500
44501 }
44502
44503 copy( source, recursive ) {
44504
44505 super.copy( source, recursive );
44506
44507 this.distance = source.distance;
44508 this.angle = source.angle;
44509 this.penumbra = source.penumbra;
44510 this.decay = source.decay;
44511
44512 this.target = source.target.clone();
44513
44514 this.shadow = source.shadow.clone();
44515
44516 return this;
44517
44518 }
44519
44520 }
44521
44522 const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
44523 const _lightPositionWorld = /*@__PURE__*/ new Vector3();
44524 const _lookTarget = /*@__PURE__*/ new Vector3();
44525
44526 class PointLightShadow extends LightShadow {
44527
44528 constructor() {
44529
44530 super( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
44531
44532 this.isPointLightShadow = true;
44533
44534 this._frameExtents = new Vector2( 4, 2 );
44535
44536 this._viewportCount = 6;
44537
44538 this._viewports = [
44539 // These viewports map a cube-map onto a 2D texture with the
44540 // following orientation:
44541 //
44542 // xzXZ
44543 // y Y
44544 //
44545 // X - Positive x direction
44546 // x - Negative x direction
44547 // Y - Positive y direction
44548 // y - Negative y direction
44549 // Z - Positive z direction
44550 // z - Negative z direction
44551
44552 // positive X
44553 new Vector4( 2, 1, 1, 1 ),
44554 // negative X
44555 new Vector4( 0, 1, 1, 1 ),
44556 // positive Z
44557 new Vector4( 3, 1, 1, 1 ),
44558 // negative Z
44559 new Vector4( 1, 1, 1, 1 ),
44560 // positive Y
44561 new Vector4( 3, 0, 1, 1 ),
44562 // negative Y
44563 new Vector4( 1, 0, 1, 1 )
44564 ];
44565
44566 this._cubeDirections = [
44567 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
44568 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
44569 ];
44570
44571 this._cubeUps = [
44572 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
44573 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
44574 ];
44575
44576 }
44577
44578 updateMatrices( light, viewportIndex = 0 ) {
44579
44580 const camera = this.camera;
44581 const shadowMatrix = this.matrix;
44582
44583 const far = light.distance || camera.far;
44584
44585 if ( far !== camera.far ) {
44586
44587 camera.far = far;
44588 camera.updateProjectionMatrix();
44589
44590 }
44591
44592 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
44593 camera.position.copy( _lightPositionWorld );
44594
44595 _lookTarget.copy( camera.position );
44596 _lookTarget.add( this._cubeDirections[ viewportIndex ] );
44597 camera.up.copy( this._cubeUps[ viewportIndex ] );
44598 camera.lookAt( _lookTarget );
44599 camera.updateMatrixWorld();
44600
44601 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
44602
44603 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
44604 this._frustum.setFromProjectionMatrix( _projScreenMatrix );
44605
44606 }
44607
44608 }
44609
44610 class PointLight extends Light {
44611
44612 constructor( color, intensity, distance = 0, decay = 2 ) {
44613
44614 super( color, intensity );
44615
44616 this.isPointLight = true;
44617
44618 this.type = 'PointLight';
44619
44620 this.distance = distance;
44621 this.decay = decay;
44622
44623 this.shadow = new PointLightShadow();
44624
44625 }
44626
44627 get power() {
44628
44629 // compute the light's luminous power (in lumens) from its intensity (in candela)
44630 // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)
44631 return this.intensity * 4 * Math.PI;
44632
44633 }
44634
44635 set power( power ) {
44636
44637 // set the light's intensity (in candela) from the desired luminous power (in lumens)
44638 this.intensity = power / ( 4 * Math.PI );
44639
44640 }
44641
44642 dispose() {
44643
44644 this.shadow.dispose();
44645
44646 }
44647
44648 copy( source, recursive ) {
44649
44650 super.copy( source, recursive );
44651
44652 this.distance = source.distance;
44653 this.decay = source.decay;
44654
44655 this.shadow = source.shadow.clone();
44656
44657 return this;
44658
44659 }
44660
44661 }
44662
44663 class DirectionalLightShadow extends LightShadow {
44664
44665 constructor() {
44666
44667 super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
44668
44669 this.isDirectionalLightShadow = true;
44670
44671 }
44672
44673 }
44674
44675 class DirectionalLight extends Light {
44676
44677 constructor( color, intensity ) {
44678
44679 super( color, intensity );
44680
44681 this.isDirectionalLight = true;
44682
44683 this.type = 'DirectionalLight';
44684
44685 this.position.copy( Object3D.DEFAULT_UP );
44686 this.updateMatrix();
44687
44688 this.target = new Object3D();
44689
44690 this.shadow = new DirectionalLightShadow();
44691
44692 }
44693
44694 dispose() {
44695
44696 this.shadow.dispose();
44697
44698 }
44699
44700 copy( source ) {
44701
44702 super.copy( source );
44703
44704 this.target = source.target.clone();
44705 this.shadow = source.shadow.clone();
44706
44707 return this;
44708
44709 }
44710
44711 }
44712
44713 class AmbientLight extends Light {
44714
44715 constructor( color, intensity ) {
44716
44717 super( color, intensity );
44718
44719 this.isAmbientLight = true;
44720
44721 this.type = 'AmbientLight';
44722
44723 }
44724
44725 }
44726
44727 class RectAreaLight extends Light {
44728
44729 constructor( color, intensity, width = 10, height = 10 ) {
44730
44731 super( color, intensity );
44732
44733 this.isRectAreaLight = true;
44734
44735 this.type = 'RectAreaLight';
44736
44737 this.width = width;
44738 this.height = height;
44739
44740 }
44741
44742 get power() {
44743
44744 // compute the light's luminous power (in lumens) from its intensity (in nits)
44745 return this.intensity * this.width * this.height * Math.PI;
44746
44747 }
44748
44749 set power( power ) {
44750
44751 // set the light's intensity (in nits) from the desired luminous power (in lumens)
44752 this.intensity = power / ( this.width * this.height * Math.PI );
44753
44754 }
44755
44756 copy( source ) {
44757
44758 super.copy( source );
44759
44760 this.width = source.width;
44761 this.height = source.height;
44762
44763 return this;
44764
44765 }
44766
44767 toJSON( meta ) {
44768
44769 const data = super.toJSON( meta );
44770
44771 data.object.width = this.width;
44772 data.object.height = this.height;
44773
44774 return data;
44775
44776 }
44777
44778 }
44779
44788 // 3-band SH defined by 9 coefficients
44789
44790 class SphericalHarmonics3 {
44791
44792 constructor() {
44793
44794 this.isSphericalHarmonics3 = true;
44795
44796 this.coefficients = [];
44797
44798 for ( let i = 0; i < 9; i ++ ) {
44799
44800 this.coefficients.push( new Vector3() );
44801
44802 }
44803
44804 }
44805
44806 set( coefficients ) {
44807
44808 for ( let i = 0; i < 9; i ++ ) {
44809
44810 this.coefficients[ i ].copy( coefficients[ i ] );
44811
44812 }
44813
44814 return this;
44815
44816 }
44817
44818 zero() {
44819
44820 for ( let i = 0; i < 9; i ++ ) {
44821
44822 this.coefficients[ i ].set( 0, 0, 0 );
44823
44824 }
44825
44826 return this;
44827
44828 }
44829
44830 // get the radiance in the direction of the normal
44831 // target is a Vector3
44832 getAt( normal, target ) {
44833
44834 // normal is assumed to be unit length
44835
44836 const x = normal.x, y = normal.y, z = normal.z;
44837
44838 const coeff = this.coefficients;
44839
44840 // band 0
44841 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
44842
44843 // band 1
44844 target.addScaledVector( coeff[ 1 ], 0.488603 * y );
44845 target.addScaledVector( coeff[ 2 ], 0.488603 * z );
44846 target.addScaledVector( coeff[ 3 ], 0.488603 * x );
44847
44848 // band 2
44849 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
44850 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
44851 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
44852 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
44853 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
44854
44855 return target;
44856
44857 }
44858
44859 // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal
44860 // target is a Vector3
44861 // https://graphics.stanford.edu/papers/envmap/envmap.pdf
44862 getIrradianceAt( normal, target ) {
44863
44864 // normal is assumed to be unit length
44865
44866 const x = normal.x, y = normal.y, z = normal.z;
44867
44868 const coeff = this.coefficients;
44869
44870 // band 0
44871 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
44872
44873 // band 1
44874 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603
44875 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
44876 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
44877
44878 // band 2
44879 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548
44880 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
44881 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3
44882 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
44883 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274
44884
44885 return target;
44886
44887 }
44888
44889 add( sh ) {
44890
44891 for ( let i = 0; i < 9; i ++ ) {
44892
44893 this.coefficients[ i ].add( sh.coefficients[ i ] );
44894
44895 }
44896
44897 return this;
44898
44899 }
44900
44901 addScaledSH( sh, s ) {
44902
44903 for ( let i = 0; i < 9; i ++ ) {
44904
44905 this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );
44906
44907 }
44908
44909 return this;
44910
44911 }
44912
44913 scale( s ) {
44914
44915 for ( let i = 0; i < 9; i ++ ) {
44916
44917 this.coefficients[ i ].multiplyScalar( s );
44918
44919 }
44920
44921 return this;
44922
44923 }
44924
44925 lerp( sh, alpha ) {
44926
44927 for ( let i = 0; i < 9; i ++ ) {
44928
44929 this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );
44930
44931 }
44932
44933 return this;
44934
44935 }
44936
44937 equals( sh ) {
44938
44939 for ( let i = 0; i < 9; i ++ ) {
44940
44941 if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {
44942
44943 return false;
44944
44945 }
44946
44947 }
44948
44949 return true;
44950
44951 }
44952
44953 copy( sh ) {
44954
44955 return this.set( sh.coefficients );
44956
44957 }
44958
44959 clone() {
44960
44961 return new this.constructor().copy( this );
44962
44963 }
44964
44965 fromArray( array, offset = 0 ) {
44966
44967 const coefficients = this.coefficients;
44968
44969 for ( let i = 0; i < 9; i ++ ) {
44970
44971 coefficients[ i ].fromArray( array, offset + ( i * 3 ) );
44972
44973 }
44974
44975 return this;
44976
44977 }
44978
44979 toArray( array = [], offset = 0 ) {
44980
44981 const coefficients = this.coefficients;
44982
44983 for ( let i = 0; i < 9; i ++ ) {
44984
44985 coefficients[ i ].toArray( array, offset + ( i * 3 ) );
44986
44987 }
44988
44989 return array;
44990
44991 }
44992
44993 // evaluate the basis functions
44994 // shBasis is an Array[ 9 ]
44995 static getBasisAt( normal, shBasis ) {
44996
44997 // normal is assumed to be unit length
44998
44999 const x = normal.x, y = normal.y, z = normal.z;
45000
45001 // band 0
45002 shBasis[ 0 ] = 0.282095;
45003
45004 // band 1
45005 shBasis[ 1 ] = 0.488603 * y;
45006 shBasis[ 2 ] = 0.488603 * z;
45007 shBasis[ 3 ] = 0.488603 * x;
45008
45009 // band 2
45010 shBasis[ 4 ] = 1.092548 * x * y;
45011 shBasis[ 5 ] = 1.092548 * y * z;
45012 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
45013 shBasis[ 7 ] = 1.092548 * x * z;
45014 shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
45015
45016 }
45017
45018 }
45019
45020 class LightProbe extends Light {
45021
45022 constructor( sh = new SphericalHarmonics3(), intensity = 1 ) {
45023
45024 super( undefined, intensity );
45025
45026 this.isLightProbe = true;
45027
45028 this.sh = sh;
45029
45030 }
45031
45032 copy( source ) {
45033
45034 super.copy( source );
45035
45036 this.sh.copy( source.sh );
45037
45038 return this;
45039
45040 }
45041
45042 fromJSON( json ) {
45043
45044 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();
45045 this.sh.fromArray( json.sh );
45046
45047 return this;
45048
45049 }
45050
45051 toJSON( meta ) {
45052
45053 const data = super.toJSON( meta );
45054
45055 data.object.sh = this.sh.toArray();
45056
45057 return data;
45058
45059 }
45060
45061 }
45062
45063 class MaterialLoader extends Loader {
45064
45065 constructor( manager ) {
45066
45067 super( manager );
45068 this.textures = {};
45069
45070 }
45071
45072 load( url, onLoad, onProgress, onError ) {
45073
45074 const scope = this;
45075
45076 const loader = new FileLoader( scope.manager );
45077 loader.setPath( scope.path );
45078 loader.setRequestHeader( scope.requestHeader );
45079 loader.setWithCredentials( scope.withCredentials );
45080 loader.load( url, function ( text ) {
45081
45082 try {
45083
45084 onLoad( scope.parse( JSON.parse( text ) ) );
45085
45086 } catch ( e ) {
45087
45088 if ( onError ) {
45089
45090 onError( e );
45091
45092 } else {
45093
45094 console.error( e );
45095
45096 }
45097
45098 scope.manager.itemError( url );
45099
45100 }
45101
45102 }, onProgress, onError );
45103
45104 }
45105
45106 parse( json ) {
45107
45108 const textures = this.textures;
45109
45110 function getTexture( name ) {
45111
45112 if ( textures[ name ] === undefined ) {
45113
45114 console.warn( 'THREE.MaterialLoader: Undefined texture', name );
45115
45116 }
45117
45118 return textures[ name ];
45119
45120 }
45121
45122 const material = MaterialLoader.createMaterialFromType( json.type );
45123
45124 if ( json.uuid !== undefined ) material.uuid = json.uuid;
45125 if ( json.name !== undefined ) material.name = json.name;
45126 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );
45127 if ( json.roughness !== undefined ) material.roughness = json.roughness;
45128 if ( json.metalness !== undefined ) material.metalness = json.metalness;
45129 if ( json.sheen !== undefined ) material.sheen = json.sheen;
45130 if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor );
45131 if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness;
45132 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
45133 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
45134 if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;
45135 if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor );
45136 if ( json.shininess !== undefined ) material.shininess = json.shininess;
45137 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
45138 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
45139 if ( json.iridescence !== undefined ) material.iridescence = json.iridescence;
45140 if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR;
45141 if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange;
45142 if ( json.transmission !== undefined ) material.transmission = json.transmission;
45143 if ( json.thickness !== undefined ) material.thickness = json.thickness;
45144 if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;
45145 if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );
45146 if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;
45147 if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation;
45148 if ( json.fog !== undefined ) material.fog = json.fog;
45149 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
45150 if ( json.blending !== undefined ) material.blending = json.blending;
45151 if ( json.combine !== undefined ) material.combine = json.combine;
45152 if ( json.side !== undefined ) material.side = json.side;
45153 if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide;
45154 if ( json.opacity !== undefined ) material.opacity = json.opacity;
45155 if ( json.transparent !== undefined ) material.transparent = json.transparent;
45156 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;
45157 if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;
45158 if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc;
45159 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest;
45160 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;
45161 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;
45162 if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc;
45163 if ( json.blendDst !== undefined ) material.blendDst = json.blendDst;
45164 if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation;
45165 if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha;
45166 if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha;
45167 if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha;
45168 if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor );
45169 if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha;
45170 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;
45171 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;
45172 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;
45173 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
45174 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;
45175 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;
45176 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;
45177 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;
45178
45179 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
45180 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;
45181 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;
45182 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;
45183
45184 if ( json.rotation !== undefined ) material.rotation = json.rotation;
45185
45186 if ( json.linewidth !== undefined ) material.linewidth = json.linewidth;
45187 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize;
45188 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize;
45189 if ( json.scale !== undefined ) material.scale = json.scale;
45190
45191 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;
45192 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;
45193 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;
45194
45195 if ( json.dithering !== undefined ) material.dithering = json.dithering;
45196
45197 if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage;
45198 if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha;
45199 if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass;
45200
45201 if ( json.visible !== undefined ) material.visible = json.visible;
45202
45203 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
45204
45205 if ( json.userData !== undefined ) material.userData = json.userData;
45206
45207 if ( json.vertexColors !== undefined ) {
45208
45209 if ( typeof json.vertexColors === 'number' ) {
45210
45211 material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
45212
45213 } else {
45214
45215 material.vertexColors = json.vertexColors;
45216
45217 }
45218
45219 }
45220
45221 // Shader Material
45222
45223 if ( json.uniforms !== undefined ) {
45224
45225 for ( const name in json.uniforms ) {
45226
45227 const uniform = json.uniforms[ name ];
45228
45229 material.uniforms[ name ] = {};
45230
45231 switch ( uniform.type ) {
45232
45233 case 't':
45234 material.uniforms[ name ].value = getTexture( uniform.value );
45235 break;
45236
45237 case 'c':
45238 material.uniforms[ name ].value = new Color().setHex( uniform.value );
45239 break;
45240
45241 case 'v2':
45242 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value );
45243 break;
45244
45245 case 'v3':
45246 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value );
45247 break;
45248
45249 case 'v4':
45250 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value );
45251 break;
45252
45253 case 'm3':
45254 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );
45255 break;
45256
45257 case 'm4':
45258 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );
45259 break;
45260
45261 default:
45262 material.uniforms[ name ].value = uniform.value;
45263
45264 }
45265
45266 }
45267
45268 }
45269
45270 if ( json.defines !== undefined ) material.defines = json.defines;
45271 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
45272 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
45273 if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion;
45274
45275 if ( json.extensions !== undefined ) {
45276
45277 for ( const key in json.extensions ) {
45278
45279 material.extensions[ key ] = json.extensions[ key ];
45280
45281 }
45282
45283 }
45284
45285 if ( json.lights !== undefined ) material.lights = json.lights;
45286 if ( json.clipping !== undefined ) material.clipping = json.clipping;
45287
45288 // for PointsMaterial
45289
45290 if ( json.size !== undefined ) material.size = json.size;
45291 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;
45292
45293 // maps
45294
45295 if ( json.map !== undefined ) material.map = getTexture( json.map );
45296 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );
45297
45298 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );
45299
45300 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );
45301 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;
45302
45303 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );
45304 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;
45305 if ( json.normalScale !== undefined ) {
45306
45307 let normalScale = json.normalScale;
45308
45309 if ( Array.isArray( normalScale ) === false ) {
45310
45311 // Blender exporter used to export a scalar. See #7459
45312
45313 normalScale = [ normalScale, normalScale ];
45314
45315 }
45316
45317 material.normalScale = new Vector2().fromArray( normalScale );
45318
45319 }
45320
45321 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );
45322 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;
45323 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;
45324
45325 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );
45326 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );
45327
45328 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );
45329 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;
45330
45331 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
45332 if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );
45333 if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap );
45334
45335 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
45336 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
45337
45338 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;
45339 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;
45340
45341 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );
45342 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;
45343
45344 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );
45345 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;
45346
45347 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
45348
45349 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );
45350 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );
45351 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
45352 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
45353
45354 if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap );
45355 if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap );
45356
45357 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
45358 if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );
45359
45360 if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );
45361
45362 if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );
45363 if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );
45364
45365 return material;
45366
45367 }
45368
45369 setTextures( value ) {
45370
45371 this.textures = value;
45372 return this;
45373
45374 }
45375
45376 static createMaterialFromType( type ) {
45377
45378 const materialLib = {
45379 ShadowMaterial,
45380 SpriteMaterial,
45381 RawShaderMaterial,
45382 ShaderMaterial,
45383 PointsMaterial,
45384 MeshPhysicalMaterial,
45385 MeshStandardMaterial,
45386 MeshPhongMaterial,
45387 MeshToonMaterial,
45388 MeshNormalMaterial,
45389 MeshLambertMaterial,
45390 MeshDepthMaterial,
45391 MeshDistanceMaterial,
45392 MeshBasicMaterial,
45393 MeshMatcapMaterial,
45394 LineDashedMaterial,
45395 LineBasicMaterial,
45396 Material
45397 };
45398
45399 return new materialLib[ type ]();
45400
45401 }
45402
45403 }
45404
45405 class LoaderUtils {
45406
45407 static decodeText( array ) {
45408
45409 if ( typeof TextDecoder !== 'undefined' ) {
45410
45411 return new TextDecoder().decode( array );
45412
45413 }
45414
45415 // Avoid the String.fromCharCode.apply(null, array) shortcut, which
45416 // throws a "maximum call stack size exceeded" error for large arrays.
45417
45418 let s = '';
45419
45420 for ( let i = 0, il = array.length; i < il; i ++ ) {
45421
45422 // Implicitly assumes little-endian.
45423 s += String.fromCharCode( array[ i ] );
45424
45425 }
45426
45427 try {
45428
45429 // merges multi-byte utf-8 characters.
45430
45431 return decodeURIComponent( escape( s ) );
45432
45433 } catch ( e ) { // see #16358
45434
45435 return s;
45436
45437 }
45438
45439 }
45440
45441 static extractUrlBase( url ) {
45442
45443 const index = url.lastIndexOf( '/' );
45444
45445 if ( index === - 1 ) return './';
45446
45447 return url.slice( 0, index + 1 );
45448
45449 }
45450
45451 static resolveURL( url, path ) {
45452
45453 // Invalid URL
45454 if ( typeof url !== 'string' || url === '' ) return '';
45455
45456 // Host Relative URL
45457 if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) {
45458
45459 path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' );
45460
45461 }
45462
45463 // Absolute URL http://,https://,//
45464 if ( /^(https?:)?\/\//i.test( url ) ) return url;
45465
45466 // Data URI
45467 if ( /^data:.*,.*$/i.test( url ) ) return url;
45468
45469 // Blob URL
45470 if ( /^blob:.*$/i.test( url ) ) return url;
45471
45472 // Relative URL
45473 return path + url;
45474
45475 }
45476
45477 }
45478
45479 class InstancedBufferGeometry extends BufferGeometry {
45480
45481 constructor() {
45482
45483 super();
45484
45485 this.isInstancedBufferGeometry = true;
45486
45487 this.type = 'InstancedBufferGeometry';
45488 this.instanceCount = Infinity;
45489
45490 }
45491
45492 copy( source ) {
45493
45494 super.copy( source );
45495
45496 this.instanceCount = source.instanceCount;
45497
45498 return this;
45499
45500 }
45501
45502 toJSON() {
45503
45504 const data = super.toJSON();
45505
45506 data.instanceCount = this.instanceCount;
45507
45508 data.isInstancedBufferGeometry = true;
45509
45510 return data;
45511
45512 }
45513
45514 }
45515
45516 class BufferGeometryLoader extends Loader {
45517
45518 constructor( manager ) {
45519
45520 super( manager );
45521
45522 }
45523
45524 load( url, onLoad, onProgress, onError ) {
45525
45526 const scope = this;
45527
45528 const loader = new FileLoader( scope.manager );
45529 loader.setPath( scope.path );
45530 loader.setRequestHeader( scope.requestHeader );
45531 loader.setWithCredentials( scope.withCredentials );
45532 loader.load( url, function ( text ) {
45533
45534 try {
45535
45536 onLoad( scope.parse( JSON.parse( text ) ) );
45537
45538 } catch ( e ) {
45539
45540 if ( onError ) {
45541
45542 onError( e );
45543
45544 } else {
45545
45546 console.error( e );
45547
45548 }
45549
45550 scope.manager.itemError( url );
45551
45552 }
45553
45554 }, onProgress, onError );
45555
45556 }
45557
45558 parse( json ) {
45559
45560 const interleavedBufferMap = {};
45561 const arrayBufferMap = {};
45562
45563 function getInterleavedBuffer( json, uuid ) {
45564
45565 if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];
45566
45567 const interleavedBuffers = json.interleavedBuffers;
45568 const interleavedBuffer = interleavedBuffers[ uuid ];
45569
45570 const buffer = getArrayBuffer( json, interleavedBuffer.buffer );
45571
45572 const array = getTypedArray( interleavedBuffer.type, buffer );
45573 const ib = new InterleavedBuffer( array, interleavedBuffer.stride );
45574 ib.uuid = interleavedBuffer.uuid;
45575
45576 interleavedBufferMap[ uuid ] = ib;
45577
45578 return ib;
45579
45580 }
45581
45582 function getArrayBuffer( json, uuid ) {
45583
45584 if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];
45585
45586 const arrayBuffers = json.arrayBuffers;
45587 const arrayBuffer = arrayBuffers[ uuid ];
45588
45589 const ab = new Uint32Array( arrayBuffer ).buffer;
45590
45591 arrayBufferMap[ uuid ] = ab;
45592
45593 return ab;
45594
45595 }
45596
45597 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();
45598
45599 const index = json.data.index;
45600
45601 if ( index !== undefined ) {
45602
45603 const typedArray = getTypedArray( index.type, index.array );
45604 geometry.setIndex( new BufferAttribute( typedArray, 1 ) );
45605
45606 }
45607
45608 const attributes = json.data.attributes;
45609
45610 for ( const key in attributes ) {
45611
45612 const attribute = attributes[ key ];
45613 let bufferAttribute;
45614
45615 if ( attribute.isInterleavedBufferAttribute ) {
45616
45617 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45618 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45619
45620 } else {
45621
45622 const typedArray = getTypedArray( attribute.type, attribute.array );
45623 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;
45624 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );
45625
45626 }
45627
45628 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45629 if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage );
45630
45631 geometry.setAttribute( key, bufferAttribute );
45632
45633 }
45634
45635 const morphAttributes = json.data.morphAttributes;
45636
45637 if ( morphAttributes ) {
45638
45639 for ( const key in morphAttributes ) {
45640
45641 const attributeArray = morphAttributes[ key ];
45642
45643 const array = [];
45644
45645 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) {
45646
45647 const attribute = attributeArray[ i ];
45648 let bufferAttribute;
45649
45650 if ( attribute.isInterleavedBufferAttribute ) {
45651
45652 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );
45653 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );
45654
45655 } else {
45656
45657 const typedArray = getTypedArray( attribute.type, attribute.array );
45658 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
45659
45660 }
45661
45662 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;
45663 array.push( bufferAttribute );
45664
45665 }
45666
45667 geometry.morphAttributes[ key ] = array;
45668
45669 }
45670
45671 }
45672
45673 const morphTargetsRelative = json.data.morphTargetsRelative;
45674
45675 if ( morphTargetsRelative ) {
45676
45677 geometry.morphTargetsRelative = true;
45678
45679 }
45680
45681 const groups = json.data.groups || json.data.drawcalls || json.data.offsets;
45682
45683 if ( groups !== undefined ) {
45684
45685 for ( let i = 0, n = groups.length; i !== n; ++ i ) {
45686
45687 const group = groups[ i ];
45688
45689 geometry.addGroup( group.start, group.count, group.materialIndex );
45690
45691 }
45692
45693 }
45694
45695 const boundingSphere = json.data.boundingSphere;
45696
45697 if ( boundingSphere !== undefined ) {
45698
45699 const center = new Vector3();
45700
45701 if ( boundingSphere.center !== undefined ) {
45702
45703 center.fromArray( boundingSphere.center );
45704
45705 }
45706
45707 geometry.boundingSphere = new Sphere( center, boundingSphere.radius );
45708
45709 }
45710
45711 if ( json.name ) geometry.name = json.name;
45712 if ( json.userData ) geometry.userData = json.userData;
45713
45714 return geometry;
45715
45716 }
45717
45718 }
45719
45720 class ObjectLoader extends Loader {
45721
45722 constructor( manager ) {
45723
45724 super( manager );
45725
45726 }
45727
45728 load( url, onLoad, onProgress, onError ) {
45729
45730 const scope = this;
45731
45732 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45733 this.resourcePath = this.resourcePath || path;
45734
45735 const loader = new FileLoader( this.manager );
45736 loader.setPath( this.path );
45737 loader.setRequestHeader( this.requestHeader );
45738 loader.setWithCredentials( this.withCredentials );
45739 loader.load( url, function ( text ) {
45740
45741 let json = null;
45742
45743 try {
45744
45745 json = JSON.parse( text );
45746
45747 } catch ( error ) {
45748
45749 if ( onError !== undefined ) onError( error );
45750
45751 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message );
45752
45753 return;
45754
45755 }
45756
45757 const metadata = json.metadata;
45758
45759 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45760
45761 if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) );
45762
45763 console.error( 'THREE.ObjectLoader: Can\'t load ' + url );
45764 return;
45765
45766 }
45767
45768 scope.parse( json, onLoad );
45769
45770 }, onProgress, onError );
45771
45772 }
45773
45774 async loadAsync( url, onProgress ) {
45775
45776 const scope = this;
45777
45778 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
45779 this.resourcePath = this.resourcePath || path;
45780
45781 const loader = new FileLoader( this.manager );
45782 loader.setPath( this.path );
45783 loader.setRequestHeader( this.requestHeader );
45784 loader.setWithCredentials( this.withCredentials );
45785
45786 const text = await loader.loadAsync( url, onProgress );
45787
45788 const json = JSON.parse( text );
45789
45790 const metadata = json.metadata;
45791
45792 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {
45793
45794 throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url );
45795
45796 }
45797
45798 return await scope.parseAsync( json );
45799
45800 }
45801
45802 parse( json, onLoad ) {
45803
45804 const animations = this.parseAnimations( json.animations );
45805 const shapes = this.parseShapes( json.shapes );
45806 const geometries = this.parseGeometries( json.geometries, shapes );
45807
45808 const images = this.parseImages( json.images, function () {
45809
45810 if ( onLoad !== undefined ) onLoad( object );
45811
45812 } );
45813
45814 const textures = this.parseTextures( json.textures, images );
45815 const materials = this.parseMaterials( json.materials, textures );
45816
45817 const object = this.parseObject( json.object, geometries, materials, textures, animations );
45818 const skeletons = this.parseSkeletons( json.skeletons, object );
45819
45820 this.bindSkeletons( object, skeletons );
45821
45822 //
45823
45824 if ( onLoad !== undefined ) {
45825
45826 let hasImages = false;
45827
45828 for ( const uuid in images ) {
45829
45830 if ( images[ uuid ].data instanceof HTMLImageElement ) {
45831
45832 hasImages = true;
45833 break;
45834
45835 }
45836
45837 }
45838
45839 if ( hasImages === false ) onLoad( object );
45840
45841 }
45842
45843 return object;
45844
45845 }
45846
45847 async parseAsync( json ) {
45848
45849 const animations = this.parseAnimations( json.animations );
45850 const shapes = this.parseShapes( json.shapes );
45851 const geometries = this.parseGeometries( json.geometries, shapes );
45852
45853 const images = await this.parseImagesAsync( json.images );
45854
45855 const textures = this.parseTextures( json.textures, images );
45856 const materials = this.parseMaterials( json.materials, textures );
45857
45858 const object = this.parseObject( json.object, geometries, materials, textures, animations );
45859 const skeletons = this.parseSkeletons( json.skeletons, object );
45860
45861 this.bindSkeletons( object, skeletons );
45862
45863 return object;
45864
45865 }
45866
45867 parseShapes( json ) {
45868
45869 const shapes = {};
45870
45871 if ( json !== undefined ) {
45872
45873 for ( let i = 0, l = json.length; i < l; i ++ ) {
45874
45875 const shape = new Shape().fromJSON( json[ i ] );
45876
45877 shapes[ shape.uuid ] = shape;
45878
45879 }
45880
45881 }
45882
45883 return shapes;
45884
45885 }
45886
45887 parseSkeletons( json, object ) {
45888
45889 const skeletons = {};
45890 const bones = {};
45891
45892 // generate bone lookup table
45893
45894 object.traverse( function ( child ) {
45895
45896 if ( child.isBone ) bones[ child.uuid ] = child;
45897
45898 } );
45899
45900 // create skeletons
45901
45902 if ( json !== undefined ) {
45903
45904 for ( let i = 0, l = json.length; i < l; i ++ ) {
45905
45906 const skeleton = new Skeleton().fromJSON( json[ i ], bones );
45907
45908 skeletons[ skeleton.uuid ] = skeleton;
45909
45910 }
45911
45912 }
45913
45914 return skeletons;
45915
45916 }
45917
45918 parseGeometries( json, shapes ) {
45919
45920 const geometries = {};
45921
45922 if ( json !== undefined ) {
45923
45924 const bufferGeometryLoader = new BufferGeometryLoader();
45925
45926 for ( let i = 0, l = json.length; i < l; i ++ ) {
45927
45928 let geometry;
45929 const data = json[ i ];
45930
45931 switch ( data.type ) {
45932
45933 case 'BufferGeometry':
45934 case 'InstancedBufferGeometry':
45935
45936 geometry = bufferGeometryLoader.parse( data );
45937 break;
45938
45939 default:
45940
45941 if ( data.type in Geometries ) {
45942
45943 geometry = Geometries[ data.type ].fromJSON( data, shapes );
45944
45945 } else {
45946
45947 console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` );
45948
45949 }
45950
45951 }
45952
45953 geometry.uuid = data.uuid;
45954
45955 if ( data.name !== undefined ) geometry.name = data.name;
45956 if ( data.userData !== undefined ) geometry.userData = data.userData;
45957
45958 geometries[ data.uuid ] = geometry;
45959
45960 }
45961
45962 }
45963
45964 return geometries;
45965
45966 }
45967
45968 parseMaterials( json, textures ) {
45969
45970 const cache = {}; // MultiMaterial
45971 const materials = {};
45972
45973 if ( json !== undefined ) {
45974
45975 const loader = new MaterialLoader();
45976 loader.setTextures( textures );
45977
45978 for ( let i = 0, l = json.length; i < l; i ++ ) {
45979
45980 const data = json[ i ];
45981
45982 if ( cache[ data.uuid ] === undefined ) {
45983
45984 cache[ data.uuid ] = loader.parse( data );
45985
45986 }
45987
45988 materials[ data.uuid ] = cache[ data.uuid ];
45989
45990 }
45991
45992 }
45993
45994 return materials;
45995
45996 }
45997
45998 parseAnimations( json ) {
45999
46000 const animations = {};
46001
46002 if ( json !== undefined ) {
46003
46004 for ( let i = 0; i < json.length; i ++ ) {
46005
46006 const data = json[ i ];
46007
46008 const clip = AnimationClip.parse( data );
46009
46010 animations[ clip.uuid ] = clip;
46011
46012 }
46013
46014 }
46015
46016 return animations;
46017
46018 }
46019
46020 parseImages( json, onLoad ) {
46021
46022 const scope = this;
46023 const images = {};
46024
46025 let loader;
46026
46027 function loadImage( url ) {
46028
46029 scope.manager.itemStart( url );
46030
46031 return loader.load( url, function () {
46032
46033 scope.manager.itemEnd( url );
46034
46035 }, undefined, function () {
46036
46037 scope.manager.itemError( url );
46038 scope.manager.itemEnd( url );
46039
46040 } );
46041
46042 }
46043
46044 function deserializeImage( image ) {
46045
46046 if ( typeof image === 'string' ) {
46047
46048 const url = image;
46049
46050 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46051
46052 return loadImage( path );
46053
46054 } else {
46055
46056 if ( image.data ) {
46057
46058 return {
46059 data: getTypedArray( image.type, image.data ),
46060 width: image.width,
46061 height: image.height
46062 };
46063
46064 } else {
46065
46066 return null;
46067
46068 }
46069
46070 }
46071
46072 }
46073
46074 if ( json !== undefined && json.length > 0 ) {
46075
46076 const manager = new LoadingManager( onLoad );
46077
46078 loader = new ImageLoader( manager );
46079 loader.setCrossOrigin( this.crossOrigin );
46080
46081 for ( let i = 0, il = json.length; i < il; i ++ ) {
46082
46083 const image = json[ i ];
46084 const url = image.url;
46085
46086 if ( Array.isArray( url ) ) {
46087
46088 // load array of images e.g CubeTexture
46089
46090 const imageArray = [];
46091
46092 for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46093
46094 const currentUrl = url[ j ];
46095
46096 const deserializedImage = deserializeImage( currentUrl );
46097
46098 if ( deserializedImage !== null ) {
46099
46100 if ( deserializedImage instanceof HTMLImageElement ) {
46101
46102 imageArray.push( deserializedImage );
46103
46104 } else {
46105
46106 // special case: handle array of data textures for cube textures
46107
46108 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46109
46110 }
46111
46112 }
46113
46114 }
46115
46116 images[ image.uuid ] = new Source( imageArray );
46117
46118 } else {
46119
46120 // load single image
46121
46122 const deserializedImage = deserializeImage( image.url );
46123 images[ image.uuid ] = new Source( deserializedImage );
46124
46125
46126 }
46127
46128 }
46129
46130 }
46131
46132 return images;
46133
46134 }
46135
46136 async parseImagesAsync( json ) {
46137
46138 const scope = this;
46139 const images = {};
46140
46141 let loader;
46142
46143 async function deserializeImage( image ) {
46144
46145 if ( typeof image === 'string' ) {
46146
46147 const url = image;
46148
46149 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url;
46150
46151 return await loader.loadAsync( path );
46152
46153 } else {
46154
46155 if ( image.data ) {
46156
46157 return {
46158 data: getTypedArray( image.type, image.data ),
46159 width: image.width,
46160 height: image.height
46161 };
46162
46163 } else {
46164
46165 return null;
46166
46167 }
46168
46169 }
46170
46171 }
46172
46173 if ( json !== undefined && json.length > 0 ) {
46174
46175 loader = new ImageLoader( this.manager );
46176 loader.setCrossOrigin( this.crossOrigin );
46177
46178 for ( let i = 0, il = json.length; i < il; i ++ ) {
46179
46180 const image = json[ i ];
46181 const url = image.url;
46182
46183 if ( Array.isArray( url ) ) {
46184
46185 // load array of images e.g CubeTexture
46186
46187 const imageArray = [];
46188
46189 for ( let j = 0, jl = url.length; j < jl; j ++ ) {
46190
46191 const currentUrl = url[ j ];
46192
46193 const deserializedImage = await deserializeImage( currentUrl );
46194
46195 if ( deserializedImage !== null ) {
46196
46197 if ( deserializedImage instanceof HTMLImageElement ) {
46198
46199 imageArray.push( deserializedImage );
46200
46201 } else {
46202
46203 // special case: handle array of data textures for cube textures
46204
46205 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );
46206
46207 }
46208
46209 }
46210
46211 }
46212
46213 images[ image.uuid ] = new Source( imageArray );
46214
46215 } else {
46216
46217 // load single image
46218
46219 const deserializedImage = await deserializeImage( image.url );
46220 images[ image.uuid ] = new Source( deserializedImage );
46221
46222 }
46223
46224 }
46225
46226 }
46227
46228 return images;
46229
46230 }
46231
46232 parseTextures( json, images ) {
46233
46234 function parseConstant( value, type ) {
46235
46236 if ( typeof value === 'number' ) return value;
46237
46238 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );
46239
46240 return type[ value ];
46241
46242 }
46243
46244 const textures = {};
46245
46246 if ( json !== undefined ) {
46247
46248 for ( let i = 0, l = json.length; i < l; i ++ ) {
46249
46250 const data = json[ i ];
46251
46252 if ( data.image === undefined ) {
46253
46254 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid );
46255
46256 }
46257
46258 if ( images[ data.image ] === undefined ) {
46259
46260 console.warn( 'THREE.ObjectLoader: Undefined image', data.image );
46261
46262 }
46263
46264 const source = images[ data.image ];
46265 const image = source.data;
46266
46267 let texture;
46268
46269 if ( Array.isArray( image ) ) {
46270
46271 texture = new CubeTexture();
46272
46273 if ( image.length === 6 ) texture.needsUpdate = true;
46274
46275 } else {
46276
46277 if ( image && image.data ) {
46278
46279 texture = new DataTexture();
46280
46281 } else {
46282
46283 texture = new Texture();
46284
46285 }
46286
46287 if ( image ) texture.needsUpdate = true; // textures can have undefined image data
46288
46289 }
46290
46291 texture.source = source;
46292
46293 texture.uuid = data.uuid;
46294
46295 if ( data.name !== undefined ) texture.name = data.name;
46296
46297 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );
46298 if ( data.channel !== undefined ) texture.channel = data.channel;
46299
46300 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset );
46301 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );
46302 if ( data.center !== undefined ) texture.center.fromArray( data.center );
46303 if ( data.rotation !== undefined ) texture.rotation = data.rotation;
46304
46305 if ( data.wrap !== undefined ) {
46306
46307 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );
46308 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );
46309
46310 }
46311
46312 if ( data.format !== undefined ) texture.format = data.format;
46313 if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat;
46314 if ( data.type !== undefined ) texture.type = data.type;
46315 if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace;
46316 if ( data.encoding !== undefined ) texture.encoding = data.encoding; // @deprecated, r152
46317
46318 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );
46319 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );
46320 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;
46321
46322 if ( data.flipY !== undefined ) texture.flipY = data.flipY;
46323
46324 if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps;
46325 if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
46326 if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
46327 if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;
46328
46329 if ( data.userData !== undefined ) texture.userData = data.userData;
46330
46331 textures[ data.uuid ] = texture;
46332
46333 }
46334
46335 }
46336
46337 return textures;
46338
46339 }
46340
46341 parseObject( data, geometries, materials, textures, animations ) {
46342
46343 let object;
46344
46345 function getGeometry( name ) {
46346
46347 if ( geometries[ name ] === undefined ) {
46348
46349 console.warn( 'THREE.ObjectLoader: Undefined geometry', name );
46350
46351 }
46352
46353 return geometries[ name ];
46354
46355 }
46356
46357 function getMaterial( name ) {
46358
46359 if ( name === undefined ) return undefined;
46360
46361 if ( Array.isArray( name ) ) {
46362
46363 const array = [];
46364
46365 for ( let i = 0, l = name.length; i < l; i ++ ) {
46366
46367 const uuid = name[ i ];
46368
46369 if ( materials[ uuid ] === undefined ) {
46370
46371 console.warn( 'THREE.ObjectLoader: Undefined material', uuid );
46372
46373 }
46374
46375 array.push( materials[ uuid ] );
46376
46377 }
46378
46379 return array;
46380
46381 }
46382
46383 if ( materials[ name ] === undefined ) {
46384
46385 console.warn( 'THREE.ObjectLoader: Undefined material', name );
46386
46387 }
46388
46389 return materials[ name ];
46390
46391 }
46392
46393 function getTexture( uuid ) {
46394
46395 if ( textures[ uuid ] === undefined ) {
46396
46397 console.warn( 'THREE.ObjectLoader: Undefined texture', uuid );
46398
46399 }
46400
46401 return textures[ uuid ];
46402
46403 }
46404
46405 let geometry, material;
46406
46407 switch ( data.type ) {
46408
46409 case 'Scene':
46410
46411 object = new Scene();
46412
46413 if ( data.background !== undefined ) {
46414
46415 if ( Number.isInteger( data.background ) ) {
46416
46417 object.background = new Color( data.background );
46418
46419 } else {
46420
46421 object.background = getTexture( data.background );
46422
46423 }
46424
46425 }
46426
46427 if ( data.environment !== undefined ) {
46428
46429 object.environment = getTexture( data.environment );
46430
46431 }
46432
46433 if ( data.fog !== undefined ) {
46434
46435 if ( data.fog.type === 'Fog' ) {
46436
46437 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );
46438
46439 } else if ( data.fog.type === 'FogExp2' ) {
46440
46441 object.fog = new FogExp2( data.fog.color, data.fog.density );
46442
46443 }
46444
46445 if ( data.fog.name !== '' ) {
46446
46447 object.fog.name = data.fog.name;
46448
46449 }
46450
46451 }
46452
46453 if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness;
46454 if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity;
46455
46456 break;
46457
46458 case 'PerspectiveCamera':
46459
46460 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
46461
46462 if ( data.focus !== undefined ) object.focus = data.focus;
46463 if ( data.zoom !== undefined ) object.zoom = data.zoom;
46464 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;
46465 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;
46466 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46467
46468 break;
46469
46470 case 'OrthographicCamera':
46471
46472 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
46473
46474 if ( data.zoom !== undefined ) object.zoom = data.zoom;
46475 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view );
46476
46477 break;
46478
46479 case 'AmbientLight':
46480
46481 object = new AmbientLight( data.color, data.intensity );
46482
46483 break;
46484
46485 case 'DirectionalLight':
46486
46487 object = new DirectionalLight( data.color, data.intensity );
46488
46489 break;
46490
46491 case 'PointLight':
46492
46493 object = new PointLight( data.color, data.intensity, data.distance, data.decay );
46494
46495 break;
46496
46497 case 'RectAreaLight':
46498
46499 object = new RectAreaLight( data.color, data.intensity, data.width, data.height );
46500
46501 break;
46502
46503 case 'SpotLight':
46504
46505 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );
46506
46507 break;
46508
46509 case 'HemisphereLight':
46510
46511 object = new HemisphereLight( data.color, data.groundColor, data.intensity );
46512
46513 break;
46514
46515 case 'LightProbe':
46516
46517 object = new LightProbe().fromJSON( data );
46518
46519 break;
46520
46521 case 'SkinnedMesh':
46522
46523 geometry = getGeometry( data.geometry );
46524 material = getMaterial( data.material );
46525
46526 object = new SkinnedMesh( geometry, material );
46527
46528 if ( data.bindMode !== undefined ) object.bindMode = data.bindMode;
46529 if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );
46530 if ( data.skeleton !== undefined ) object.skeleton = data.skeleton;
46531
46532 break;
46533
46534 case 'Mesh':
46535
46536 geometry = getGeometry( data.geometry );
46537 material = getMaterial( data.material );
46538
46539 object = new Mesh( geometry, material );
46540
46541 break;
46542
46543 case 'InstancedMesh':
46544
46545 geometry = getGeometry( data.geometry );
46546 material = getMaterial( data.material );
46547 const count = data.count;
46548 const instanceMatrix = data.instanceMatrix;
46549 const instanceColor = data.instanceColor;
46550
46551 object = new InstancedMesh( geometry, material, count );
46552 object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 );
46553 if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize );
46554
46555 break;
46556
46557 case 'BatchedMesh':
46558
46559 geometry = getGeometry( data.geometry );
46560 material = getMaterial( data.material );
46561
46562 object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material );
46563 object.geometry = geometry;
46564 object.perObjectFrustumCulled = data.perObjectFrustumCulled;
46565 object.sortObjects = data.sortObjects;
46566
46567 object._drawRanges = data.drawRanges;
46568 object._reservedRanges = data.reservedRanges;
46569
46570 object._visibility = data.visibility;
46571 object._active = data.active;
46572 object._bounds = data.bounds.map( bound => {
46573
46574 const box = new Box3();
46575 box.min.fromArray( bound.boxMin );
46576 box.max.fromArray( bound.boxMax );
46577
46578 const sphere = new Sphere();
46579 sphere.radius = bound.sphereRadius;
46580 sphere.center.fromArray( bound.sphereCenter );
46581
46582 return {
46583 boxInitialized: bound.boxInitialized,
46584 box: box,
46585
46586 sphereInitialized: bound.sphereInitialized,
46587 sphere: sphere
46588 };
46589
46590 } );
46591
46592 object._maxGeometryCount = data.maxGeometryCount;
46593 object._maxVertexCount = data.maxVertexCount;
46594 object._maxIndexCount = data.maxIndexCount;
46595
46596 object._geometryInitialized = data.geometryInitialized;
46597 object._geometryCount = data.geometryCount;
46598
46599 object._matricesTexture = getTexture( data.matricesTexture.uuid );
46600
46601 break;
46602
46603 case 'LOD':
46604
46605 object = new LOD();
46606
46607 break;
46608
46609 case 'Line':
46610
46611 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );
46612
46613 break;
46614
46615 case 'LineLoop':
46616
46617 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );
46618
46619 break;
46620
46621 case 'LineSegments':
46622
46623 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );
46624
46625 break;
46626
46627 case 'PointCloud':
46628 case 'Points':
46629
46630 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );
46631
46632 break;
46633
46634 case 'Sprite':
46635
46636 object = new Sprite( getMaterial( data.material ) );
46637
46638 break;
46639
46640 case 'Group':
46641
46642 object = new Group();
46643
46644 break;
46645
46646 case 'Bone':
46647
46648 object = new Bone();
46649
46650 break;
46651
46652 default:
46653
46654 object = new Object3D();
46655
46656 }
46657
46658 object.uuid = data.uuid;
46659
46660 if ( data.name !== undefined ) object.name = data.name;
46661
46662 if ( data.matrix !== undefined ) {
46663
46664 object.matrix.fromArray( data.matrix );
46665
46666 if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;
46667 if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );
46668
46669 } else {
46670
46671 if ( data.position !== undefined ) object.position.fromArray( data.position );
46672 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
46673 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );
46674 if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
46675
46676 }
46677
46678 if ( data.up !== undefined ) object.up.fromArray( data.up );
46679
46680 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow;
46681 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;
46682
46683 if ( data.shadow ) {
46684
46685 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;
46686 if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;
46687 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;
46688 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );
46689 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );
46690
46691 }
46692
46693 if ( data.visible !== undefined ) object.visible = data.visible;
46694 if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;
46695 if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;
46696 if ( data.userData !== undefined ) object.userData = data.userData;
46697 if ( data.layers !== undefined ) object.layers.mask = data.layers;
46698
46699 if ( data.children !== undefined ) {
46700
46701 const children = data.children;
46702
46703 for ( let i = 0; i < children.length; i ++ ) {
46704
46705 object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) );
46706
46707 }
46708
46709 }
46710
46711 if ( data.animations !== undefined ) {
46712
46713 const objectAnimations = data.animations;
46714
46715 for ( let i = 0; i < objectAnimations.length; i ++ ) {
46716
46717 const uuid = objectAnimations[ i ];
46718
46719 object.animations.push( animations[ uuid ] );
46720
46721 }
46722
46723 }
46724
46725 if ( data.type === 'LOD' ) {
46726
46727 if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;
46728
46729 const levels = data.levels;
46730
46731 for ( let l = 0; l < levels.length; l ++ ) {
46732
46733 const level = levels[ l ];
46734 const child = object.getObjectByProperty( 'uuid', level.object );
46735
46736 if ( child !== undefined ) {
46737
46738 object.addLevel( child, level.distance, level.hysteresis );
46739
46740 }
46741
46742 }
46743
46744 }
46745
46746 return object;
46747
46748 }
46749
46750 bindSkeletons( object, skeletons ) {
46751
46752 if ( Object.keys( skeletons ).length === 0 ) return;
46753
46754 object.traverse( function ( child ) {
46755
46756 if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {
46757
46758 const skeleton = skeletons[ child.skeleton ];
46759
46760 if ( skeleton === undefined ) {
46761
46762 console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );
46763
46764 } else {
46765
46766 child.bind( skeleton, child.bindMatrix );
46767
46768 }
46769
46770 }
46771
46772 } );
46773
46774 }
46775
46776 }
46777
46778 const TEXTURE_MAPPING = {
46779 UVMapping: UVMapping,
46780 CubeReflectionMapping: CubeReflectionMapping,
46781 CubeRefractionMapping: CubeRefractionMapping,
46782 EquirectangularReflectionMapping: EquirectangularReflectionMapping,
46783 EquirectangularRefractionMapping: EquirectangularRefractionMapping,
46784 CubeUVReflectionMapping: CubeUVReflectionMapping
46785 };
46786
46787 const TEXTURE_WRAPPING = {
46788 RepeatWrapping: RepeatWrapping,
46789 ClampToEdgeWrapping: ClampToEdgeWrapping,
46790 MirroredRepeatWrapping: MirroredRepeatWrapping
46791 };
46792
46793 const TEXTURE_FILTER = {
46794 NearestFilter: NearestFilter,
46795 NearestMipmapNearestFilter: NearestMipmapNearestFilter,
46796 NearestMipmapLinearFilter: NearestMipmapLinearFilter,
46797 LinearFilter: LinearFilter,
46798 LinearMipmapNearestFilter: LinearMipmapNearestFilter,
46799 LinearMipmapLinearFilter: LinearMipmapLinearFilter
46800 };
46801
46802 class ImageBitmapLoader extends Loader {
46803
46804 constructor( manager ) {
46805
46806 super( manager );
46807
46808 this.isImageBitmapLoader = true;
46809
46810 if ( typeof createImageBitmap === 'undefined' ) {
46811
46812 console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );
46813
46814 }
46815
46816 if ( typeof fetch === 'undefined' ) {
46817
46818 console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );
46819
46820 }
46821
46822 this.options = { premultiplyAlpha: 'none' };
46823
46824 }
46825
46826 setOptions( options ) {
46827
46828 this.options = options;
46829
46830 return this;
46831
46832 }
46833
46834 load( url, onLoad, onProgress, onError ) {
46835
46836 if ( url === undefined ) url = '';
46837
46838 if ( this.path !== undefined ) url = this.path + url;
46839
46840 url = this.manager.resolveURL( url );
46841
46842 const scope = this;
46843
46844 const cached = Cache.get( url );
46845
46846 if ( cached !== undefined ) {
46847
46848 scope.manager.itemStart( url );
46849
46850 // If cached is a promise, wait for it to resolve
46851 if ( cached.then ) {
46852
46853 cached.then( imageBitmap => {
46854
46855 if ( onLoad ) onLoad( imageBitmap );
46856
46857 scope.manager.itemEnd( url );
46858
46859 } ).catch( e => {
46860
46861 if ( onError ) onError( e );
46862
46863 } );
46864 return;
46865
46866 }
46867
46868 // If cached is not a promise (i.e., it's already an imageBitmap)
46869 setTimeout( function () {
46870
46871 if ( onLoad ) onLoad( cached );
46872
46873 scope.manager.itemEnd( url );
46874
46875 }, 0 );
46876
46877 return cached;
46878
46879 }
46880
46881 const fetchOptions = {};
46882 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
46883 fetchOptions.headers = this.requestHeader;
46884
46885 const promise = fetch( url, fetchOptions ).then( function ( res ) {
46886
46887 return res.blob();
46888
46889 } ).then( function ( blob ) {
46890
46891 return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );
46892
46893 } ).then( function ( imageBitmap ) {
46894
46895 Cache.add( url, imageBitmap );
46896
46897 if ( onLoad ) onLoad( imageBitmap );
46898
46899 scope.manager.itemEnd( url );
46900
46901 return imageBitmap;
46902
46903 } ).catch( function ( e ) {
46904
46905 if ( onError ) onError( e );
46906
46907 Cache.remove( url );
46908
46909 scope.manager.itemError( url );
46910 scope.manager.itemEnd( url );
46911
46912 } );
46913
46914 Cache.add( url, promise );
46915 scope.manager.itemStart( url );
46916
46917 }
46918
46919 }
46920
46921 let _context;
46922
46923 class AudioContext {
46924
46925 static getContext() {
46926
46927 if ( _context === undefined ) {
46928
46929 _context = new ( window.AudioContext || window.webkitAudioContext )();
46930
46931 }
46932
46933 return _context;
46934
46935 }
46936
46937 static setContext( value ) {
46938
46939 _context = value;
46940
46941 }
46942
46943 }
46944
46945 class AudioLoader extends Loader {
46946
46947 constructor( manager ) {
46948
46949 super( manager );
46950
46951 }
46952
46953 load( url, onLoad, onProgress, onError ) {
46954
46955 const scope = this;
46956
46957 const loader = new FileLoader( this.manager );
46958 loader.setResponseType( 'arraybuffer' );
46959 loader.setPath( this.path );
46960 loader.setRequestHeader( this.requestHeader );
46961 loader.setWithCredentials( this.withCredentials );
46962 loader.load( url, function ( buffer ) {
46963
46964 try {
46965
46966 // Create a copy of the buffer. The `decodeAudioData` method
46967 // detaches the buffer when complete, preventing reuse.
46968 const bufferCopy = buffer.slice( 0 );
46969
46970 const context = AudioContext.getContext();
46971 context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
46972
46973 onLoad( audioBuffer );
46974
46975 } ).catch( handleError );
46976
46977 } catch ( e ) {
46978
46979 handleError( e );
46980
46981 }
46982
46983 }, onProgress, onError );
46984
46985 function handleError( e ) {
46986
46987 if ( onError ) {
46988
46989 onError( e );
46990
46991 } else {
46992
46993 console.error( e );
46994
46995 }
46996
46997 scope.manager.itemError( url );
46998
46999 }
47000
47001 }
47002
47003 }
47004
47005 const _eyeRight = /*@__PURE__*/ new Matrix4();
47006 const _eyeLeft = /*@__PURE__*/ new Matrix4();
47007 const _projectionMatrix = /*@__PURE__*/ new Matrix4();
47008
47009 class StereoCamera {
47010
47011 constructor() {
47012
47013 this.type = 'StereoCamera';
47014
47015 this.aspect = 1;
47016
47017 this.eyeSep = 0.064;
47018
47019 this.cameraL = new PerspectiveCamera();
47020 this.cameraL.layers.enable( 1 );
47021 this.cameraL.matrixAutoUpdate = false;
47022
47023 this.cameraR = new PerspectiveCamera();
47024 this.cameraR.layers.enable( 2 );
47025 this.cameraR.matrixAutoUpdate = false;
47026
47027 this._cache = {
47028 focus: null,
47029 fov: null,
47030 aspect: null,
47031 near: null,
47032 far: null,
47033 zoom: null,
47034 eyeSep: null
47035 };
47036
47037 }
47038
47039 update( camera ) {
47040
47041 const cache = this._cache;
47042
47043 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||
47044 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||
47045 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;
47046
47047 if ( needsUpdate ) {
47048
47049 cache.focus = camera.focus;
47050 cache.fov = camera.fov;
47051 cache.aspect = camera.aspect * this.aspect;
47052 cache.near = camera.near;
47053 cache.far = camera.far;
47054 cache.zoom = camera.zoom;
47055 cache.eyeSep = this.eyeSep;
47056
47057 // Off-axis stereoscopic effect based on
47058 // http://paulbourke.net/stereographics/stereorender/
47059
47060 _projectionMatrix.copy( camera.projectionMatrix );
47061 const eyeSepHalf = cache.eyeSep / 2;
47062 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
47063 const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;
47064 let xmin, xmax;
47065
47066 // translate xOffset
47067
47068 _eyeLeft.elements[ 12 ] = - eyeSepHalf;
47069 _eyeRight.elements[ 12 ] = eyeSepHalf;
47070
47071 // for left eye
47072
47073 xmin = - ymax * cache.aspect + eyeSepOnProjection;
47074 xmax = ymax * cache.aspect + eyeSepOnProjection;
47075
47076 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47077 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47078
47079 this.cameraL.projectionMatrix.copy( _projectionMatrix );
47080
47081 // for right eye
47082
47083 xmin = - ymax * cache.aspect - eyeSepOnProjection;
47084 xmax = ymax * cache.aspect - eyeSepOnProjection;
47085
47086 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );
47087 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
47088
47089 this.cameraR.projectionMatrix.copy( _projectionMatrix );
47090
47091 }
47092
47093 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );
47094 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );
47095
47096 }
47097
47098 }
47099
47100 class Clock {
47101
47102 constructor( autoStart = true ) {
47103
47104 this.autoStart = autoStart;
47105
47106 this.startTime = 0;
47107 this.oldTime = 0;
47108 this.elapsedTime = 0;
47109
47110 this.running = false;
47111
47112 }
47113
47114 start() {
47115
47116 this.startTime = now();
47117
47118 this.oldTime = this.startTime;
47119 this.elapsedTime = 0;
47120 this.running = true;
47121
47122 }
47123
47124 stop() {
47125
47126 this.getElapsedTime();
47127 this.running = false;
47128 this.autoStart = false;
47129
47130 }
47131
47132 getElapsedTime() {
47133
47134 this.getDelta();
47135 return this.elapsedTime;
47136
47137 }
47138
47139 getDelta() {
47140
47141 let diff = 0;
47142
47143 if ( this.autoStart && ! this.running ) {
47144
47145 this.start();
47146 return 0;
47147
47148 }
47149
47150 if ( this.running ) {
47151
47152 const newTime = now();
47153
47154 diff = ( newTime - this.oldTime ) / 1000;
47155 this.oldTime = newTime;
47156
47157 this.elapsedTime += diff;
47158
47159 }
47160
47161 return diff;
47162
47163 }
47164
47165 }
47166
47167 function now() {
47168
47169 return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
47170
47171 }
47172
47173 const _position$1 = /*@__PURE__*/ new Vector3();
47174 const _quaternion$1 = /*@__PURE__*/ new Quaternion();
47175 const _scale$1 = /*@__PURE__*/ new Vector3();
47176 const _orientation$1 = /*@__PURE__*/ new Vector3();
47177
47178 class AudioListener extends Object3D {
47179
47180 constructor() {
47181
47182 super();
47183
47184 this.type = 'AudioListener';
47185
47186 this.context = AudioContext.getContext();
47187
47188 this.gain = this.context.createGain();
47189 this.gain.connect( this.context.destination );
47190
47191 this.filter = null;
47192
47193 this.timeDelta = 0;
47194
47195 // private
47196
47197 this._clock = new Clock();
47198
47199 }
47200
47201 getInput() {
47202
47203 return this.gain;
47204
47205 }
47206
47207 removeFilter() {
47208
47209 if ( this.filter !== null ) {
47210
47211 this.gain.disconnect( this.filter );
47212 this.filter.disconnect( this.context.destination );
47213 this.gain.connect( this.context.destination );
47214 this.filter = null;
47215
47216 }
47217
47218 return this;
47219
47220 }
47221
47222 getFilter() {
47223
47224 return this.filter;
47225
47226 }
47227
47228 setFilter( value ) {
47229
47230 if ( this.filter !== null ) {
47231
47232 this.gain.disconnect( this.filter );
47233 this.filter.disconnect( this.context.destination );
47234
47235 } else {
47236
47237 this.gain.disconnect( this.context.destination );
47238
47239 }
47240
47241 this.filter = value;
47242 this.gain.connect( this.filter );
47243 this.filter.connect( this.context.destination );
47244
47245 return this;
47246
47247 }
47248
47249 getMasterVolume() {
47250
47251 return this.gain.gain.value;
47252
47253 }
47254
47255 setMasterVolume( value ) {
47256
47257 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47258
47259 return this;
47260
47261 }
47262
47263 updateMatrixWorld( force ) {
47264
47265 super.updateMatrixWorld( force );
47266
47267 const listener = this.context.listener;
47268 const up = this.up;
47269
47270 this.timeDelta = this._clock.getDelta();
47271
47272 this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );
47273
47274 _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 );
47275
47276 if ( listener.positionX ) {
47277
47278 // code path for Chrome (see #14393)
47279
47280 const endTime = this.context.currentTime + this.timeDelta;
47281
47282 listener.positionX.linearRampToValueAtTime( _position$1.x, endTime );
47283 listener.positionY.linearRampToValueAtTime( _position$1.y, endTime );
47284 listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );
47285 listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime );
47286 listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime );
47287 listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime );
47288 listener.upX.linearRampToValueAtTime( up.x, endTime );
47289 listener.upY.linearRampToValueAtTime( up.y, endTime );
47290 listener.upZ.linearRampToValueAtTime( up.z, endTime );
47291
47292 } else {
47293
47294 listener.setPosition( _position$1.x, _position$1.y, _position$1.z );
47295 listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z );
47296
47297 }
47298
47299 }
47300
47301 }
47302
47303 class Audio extends Object3D {
47304
47305 constructor( listener ) {
47306
47307 super();
47308
47309 this.type = 'Audio';
47310
47311 this.listener = listener;
47312 this.context = listener.context;
47313
47314 this.gain = this.context.createGain();
47315 this.gain.connect( listener.getInput() );
47316
47317 this.autoplay = false;
47318
47319 this.buffer = null;
47320 this.detune = 0;
47321 this.loop = false;
47322 this.loopStart = 0;
47323 this.loopEnd = 0;
47324 this.offset = 0;
47325 this.duration = undefined;
47326 this.playbackRate = 1;
47327 this.isPlaying = false;
47328 this.hasPlaybackControl = true;
47329 this.source = null;
47330 this.sourceType = 'empty';
47331
47332 this._startedAt = 0;
47333 this._progress = 0;
47334 this._connected = false;
47335
47336 this.filters = [];
47337
47338 }
47339
47340 getOutput() {
47341
47342 return this.gain;
47343
47344 }
47345
47346 setNodeSource( audioNode ) {
47347
47348 this.hasPlaybackControl = false;
47349 this.sourceType = 'audioNode';
47350 this.source = audioNode;
47351 this.connect();
47352
47353 return this;
47354
47355 }
47356
47357 setMediaElementSource( mediaElement ) {
47358
47359 this.hasPlaybackControl = false;
47360 this.sourceType = 'mediaNode';
47361 this.source = this.context.createMediaElementSource( mediaElement );
47362 this.connect();
47363
47364 return this;
47365
47366 }
47367
47368 setMediaStreamSource( mediaStream ) {
47369
47370 this.hasPlaybackControl = false;
47371 this.sourceType = 'mediaStreamNode';
47372 this.source = this.context.createMediaStreamSource( mediaStream );
47373 this.connect();
47374
47375 return this;
47376
47377 }
47378
47379 setBuffer( audioBuffer ) {
47380
47381 this.buffer = audioBuffer;
47382 this.sourceType = 'buffer';
47383
47384 if ( this.autoplay ) this.play();
47385
47386 return this;
47387
47388 }
47389
47390 play( delay = 0 ) {
47391
47392 if ( this.isPlaying === true ) {
47393
47394 console.warn( 'THREE.Audio: Audio is already playing.' );
47395 return;
47396
47397 }
47398
47399 if ( this.hasPlaybackControl === false ) {
47400
47401 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47402 return;
47403
47404 }
47405
47406 this._startedAt = this.context.currentTime + delay;
47407
47408 const source = this.context.createBufferSource();
47409 source.buffer = this.buffer;
47410 source.loop = this.loop;
47411 source.loopStart = this.loopStart;
47412 source.loopEnd = this.loopEnd;
47413 source.onended = this.onEnded.bind( this );
47414 source.start( this._startedAt, this._progress + this.offset, this.duration );
47415
47416 this.isPlaying = true;
47417
47418 this.source = source;
47419
47420 this.setDetune( this.detune );
47421 this.setPlaybackRate( this.playbackRate );
47422
47423 return this.connect();
47424
47425 }
47426
47427 pause() {
47428
47429 if ( this.hasPlaybackControl === false ) {
47430
47431 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47432 return;
47433
47434 }
47435
47436 if ( this.isPlaying === true ) {
47437
47438 // update current progress
47439
47440 this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;
47441
47442 if ( this.loop === true ) {
47443
47444 // ensure _progress does not exceed duration with looped audios
47445
47446 this._progress = this._progress % ( this.duration || this.buffer.duration );
47447
47448 }
47449
47450 this.source.stop();
47451 this.source.onended = null;
47452
47453 this.isPlaying = false;
47454
47455 }
47456
47457 return this;
47458
47459 }
47460
47461 stop() {
47462
47463 if ( this.hasPlaybackControl === false ) {
47464
47465 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47466 return;
47467
47468 }
47469
47470 this._progress = 0;
47471
47472 if ( this.source !== null ) {
47473
47474 this.source.stop();
47475 this.source.onended = null;
47476
47477 }
47478
47479 this.isPlaying = false;
47480
47481 return this;
47482
47483 }
47484
47485 connect() {
47486
47487 if ( this.filters.length > 0 ) {
47488
47489 this.source.connect( this.filters[ 0 ] );
47490
47491 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47492
47493 this.filters[ i - 1 ].connect( this.filters[ i ] );
47494
47495 }
47496
47497 this.filters[ this.filters.length - 1 ].connect( this.getOutput() );
47498
47499 } else {
47500
47501 this.source.connect( this.getOutput() );
47502
47503 }
47504
47505 this._connected = true;
47506
47507 return this;
47508
47509 }
47510
47511 disconnect() {
47512
47513 if ( this._connected === false ) {
47514
47515 return;
47516
47517 }
47518
47519 if ( this.filters.length > 0 ) {
47520
47521 this.source.disconnect( this.filters[ 0 ] );
47522
47523 for ( let i = 1, l = this.filters.length; i < l; i ++ ) {
47524
47525 this.filters[ i - 1 ].disconnect( this.filters[ i ] );
47526
47527 }
47528
47529 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );
47530
47531 } else {
47532
47533 this.source.disconnect( this.getOutput() );
47534
47535 }
47536
47537 this._connected = false;
47538
47539 return this;
47540
47541 }
47542
47543 getFilters() {
47544
47545 return this.filters;
47546
47547 }
47548
47549 setFilters( value ) {
47550
47551 if ( ! value ) value = [];
47552
47553 if ( this._connected === true ) {
47554
47555 this.disconnect();
47556 this.filters = value.slice();
47557 this.connect();
47558
47559 } else {
47560
47561 this.filters = value.slice();
47562
47563 }
47564
47565 return this;
47566
47567 }
47568
47569 setDetune( value ) {
47570
47571 this.detune = value;
47572
47573 if ( this.source.detune === undefined ) return; // only set detune when available
47574
47575 if ( this.isPlaying === true ) {
47576
47577 this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );
47578
47579 }
47580
47581 return this;
47582
47583 }
47584
47585 getDetune() {
47586
47587 return this.detune;
47588
47589 }
47590
47591 getFilter() {
47592
47593 return this.getFilters()[ 0 ];
47594
47595 }
47596
47597 setFilter( filter ) {
47598
47599 return this.setFilters( filter ? [ filter ] : [] );
47600
47601 }
47602
47603 setPlaybackRate( value ) {
47604
47605 if ( this.hasPlaybackControl === false ) {
47606
47607 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47608 return;
47609
47610 }
47611
47612 this.playbackRate = value;
47613
47614 if ( this.isPlaying === true ) {
47615
47616 this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );
47617
47618 }
47619
47620 return this;
47621
47622 }
47623
47624 getPlaybackRate() {
47625
47626 return this.playbackRate;
47627
47628 }
47629
47630 onEnded() {
47631
47632 this.isPlaying = false;
47633
47634 }
47635
47636 getLoop() {
47637
47638 if ( this.hasPlaybackControl === false ) {
47639
47640 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47641 return false;
47642
47643 }
47644
47645 return this.loop;
47646
47647 }
47648
47649 setLoop( value ) {
47650
47651 if ( this.hasPlaybackControl === false ) {
47652
47653 console.warn( 'THREE.Audio: this Audio has no playback control.' );
47654 return;
47655
47656 }
47657
47658 this.loop = value;
47659
47660 if ( this.isPlaying === true ) {
47661
47662 this.source.loop = this.loop;
47663
47664 }
47665
47666 return this;
47667
47668 }
47669
47670 setLoopStart( value ) {
47671
47672 this.loopStart = value;
47673
47674 return this;
47675
47676 }
47677
47678 setLoopEnd( value ) {
47679
47680 this.loopEnd = value;
47681
47682 return this;
47683
47684 }
47685
47686 getVolume() {
47687
47688 return this.gain.gain.value;
47689
47690 }
47691
47692 setVolume( value ) {
47693
47694 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
47695
47696 return this;
47697
47698 }
47699
47700 }
47701
47702 const _position = /*@__PURE__*/ new Vector3();
47703 const _quaternion = /*@__PURE__*/ new Quaternion();
47704 const _scale = /*@__PURE__*/ new Vector3();
47705 const _orientation = /*@__PURE__*/ new Vector3();
47706
47707 class PositionalAudio extends Audio {
47708
47709 constructor( listener ) {
47710
47711 super( listener );
47712
47713 this.panner = this.context.createPanner();
47714 this.panner.panningModel = 'HRTF';
47715 this.panner.connect( this.gain );
47716
47717 }
47718
47719 connect() {
47720
47721 super.connect();
47722
47723 this.panner.connect( this.gain );
47724
47725 }
47726
47727 disconnect() {
47728
47729 super.disconnect();
47730
47731 this.panner.disconnect( this.gain );
47732
47733 }
47734
47735 getOutput() {
47736
47737 return this.panner;
47738
47739 }
47740
47741 getRefDistance() {
47742
47743 return this.panner.refDistance;
47744
47745 }
47746
47747 setRefDistance( value ) {
47748
47749 this.panner.refDistance = value;
47750
47751 return this;
47752
47753 }
47754
47755 getRolloffFactor() {
47756
47757 return this.panner.rolloffFactor;
47758
47759 }
47760
47761 setRolloffFactor( value ) {
47762
47763 this.panner.rolloffFactor = value;
47764
47765 return this;
47766
47767 }
47768
47769 getDistanceModel() {
47770
47771 return this.panner.distanceModel;
47772
47773 }
47774
47775 setDistanceModel( value ) {
47776
47777 this.panner.distanceModel = value;
47778
47779 return this;
47780
47781 }
47782
47783 getMaxDistance() {
47784
47785 return this.panner.maxDistance;
47786
47787 }
47788
47789 setMaxDistance( value ) {
47790
47791 this.panner.maxDistance = value;
47792
47793 return this;
47794
47795 }
47796
47797 setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
47798
47799 this.panner.coneInnerAngle = coneInnerAngle;
47800 this.panner.coneOuterAngle = coneOuterAngle;
47801 this.panner.coneOuterGain = coneOuterGain;
47802
47803 return this;
47804
47805 }
47806
47807 updateMatrixWorld( force ) {
47808
47809 super.updateMatrixWorld( force );
47810
47811 if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
47812
47813 this.matrixWorld.decompose( _position, _quaternion, _scale );
47814
47815 _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );
47816
47817 const panner = this.panner;
47818
47819 if ( panner.positionX ) {
47820
47821 // code path for Chrome and Firefox (see #14393)
47822
47823 const endTime = this.context.currentTime + this.listener.timeDelta;
47824
47825 panner.positionX.linearRampToValueAtTime( _position.x, endTime );
47826 panner.positionY.linearRampToValueAtTime( _position.y, endTime );
47827 panner.positionZ.linearRampToValueAtTime( _position.z, endTime );
47828 panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );
47829 panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );
47830 panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );
47831
47832 } else {
47833
47834 panner.setPosition( _position.x, _position.y, _position.z );
47835 panner.setOrientation( _orientation.x, _orientation.y, _orientation.z );
47836
47837 }
47838
47839 }
47840
47841 }
47842
47843 class AudioAnalyser {
47844
47845 constructor( audio, fftSize = 2048 ) {
47846
47847 this.analyser = audio.context.createAnalyser();
47848 this.analyser.fftSize = fftSize;
47849
47850 this.data = new Uint8Array( this.analyser.frequencyBinCount );
47851
47852 audio.getOutput().connect( this.analyser );
47853
47854 }
47855
47856
47857 getFrequencyData() {
47858
47859 this.analyser.getByteFrequencyData( this.data );
47860
47861 return this.data;
47862
47863 }
47864
47865 getAverageFrequency() {
47866
47867 let value = 0;
47868 const data = this.getFrequencyData();
47869
47870 for ( let i = 0; i < data.length; i ++ ) {
47871
47872 value += data[ i ];
47873
47874 }
47875
47876 return value / data.length;
47877
47878 }
47879
47880 }
47881
47882 class PropertyMixer {
47883
47884 constructor( binding, typeName, valueSize ) {
47885
47886 this.binding = binding;
47887 this.valueSize = valueSize;
47888
47889 let mixFunction,
47890 mixFunctionAdditive,
47891 setIdentity;
47892
47893 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
47894 //
47895 // interpolators can use .buffer as their .result
47896 // the data then goes to 'incoming'
47897 //
47898 // 'accu0' and 'accu1' are used frame-interleaved for
47899 // the cumulative result and are compared to detect
47900 // changes
47901 //
47902 // 'orig' stores the original state of the property
47903 //
47904 // 'add' is used for additive cumulative results
47905 //
47906 // 'work' is optional and is only present for quaternion types. It is used
47907 // to store intermediate quaternion multiplication results
47908
47909 switch ( typeName ) {
47910
47911 case 'quaternion':
47912 mixFunction = this._slerp;
47913 mixFunctionAdditive = this._slerpAdditive;
47914 setIdentity = this._setAdditiveIdentityQuaternion;
47915
47916 this.buffer = new Float64Array( valueSize * 6 );
47917 this._workIndex = 5;
47918 break;
47919
47920 case 'string':
47921 case 'bool':
47922 mixFunction = this._select;
47923
47924 // Use the regular mix function and for additive on these types,
47925 // additive is not relevant for non-numeric types
47926 mixFunctionAdditive = this._select;
47927
47928 setIdentity = this._setAdditiveIdentityOther;
47929
47930 this.buffer = new Array( valueSize * 5 );
47931 break;
47932
47933 default:
47934 mixFunction = this._lerp;
47935 mixFunctionAdditive = this._lerpAdditive;
47936 setIdentity = this._setAdditiveIdentityNumeric;
47937
47938 this.buffer = new Float64Array( valueSize * 5 );
47939
47940 }
47941
47942 this._mixBufferRegion = mixFunction;
47943 this._mixBufferRegionAdditive = mixFunctionAdditive;
47944 this._setIdentity = setIdentity;
47945 this._origIndex = 3;
47946 this._addIndex = 4;
47947
47948 this.cumulativeWeight = 0;
47949 this.cumulativeWeightAdditive = 0;
47950
47951 this.useCount = 0;
47952 this.referenceCount = 0;
47953
47954 }
47955
47956 // accumulate data in the 'incoming' region into 'accu<i>'
47957 accumulate( accuIndex, weight ) {
47958
47959 // note: happily accumulating nothing when weight = 0, the caller knows
47960 // the weight and shouldn't have made the call in the first place
47961
47962 const buffer = this.buffer,
47963 stride = this.valueSize,
47964 offset = accuIndex * stride + stride;
47965
47966 let currentWeight = this.cumulativeWeight;
47967
47968 if ( currentWeight === 0 ) {
47969
47970 // accuN := incoming * weight
47971
47972 for ( let i = 0; i !== stride; ++ i ) {
47973
47974 buffer[ offset + i ] = buffer[ i ];
47975
47976 }
47977
47978 currentWeight = weight;
47979
47980 } else {
47981
47982 // accuN := accuN + incoming * weight
47983
47984 currentWeight += weight;
47985 const mix = weight / currentWeight;
47986 this._mixBufferRegion( buffer, offset, 0, mix, stride );
47987
47988 }
47989
47990 this.cumulativeWeight = currentWeight;
47991
47992 }
47993
47994 // accumulate data in the 'incoming' region into 'add'
47995 accumulateAdditive( weight ) {
47996
47997 const buffer = this.buffer,
47998 stride = this.valueSize,
47999 offset = stride * this._addIndex;
48000
48001 if ( this.cumulativeWeightAdditive === 0 ) {
48002
48003 // add = identity
48004
48005 this._setIdentity();
48006
48007 }
48008
48009 // add := add + incoming * weight
48010
48011 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
48012 this.cumulativeWeightAdditive += weight;
48013
48014 }
48015
48016 // apply the state of 'accu<i>' to the binding when accus differ
48017 apply( accuIndex ) {
48018
48019 const stride = this.valueSize,
48020 buffer = this.buffer,
48021 offset = accuIndex * stride + stride,
48022
48023 weight = this.cumulativeWeight,
48024 weightAdditive = this.cumulativeWeightAdditive,
48025
48026 binding = this.binding;
48027
48028 this.cumulativeWeight = 0;
48029 this.cumulativeWeightAdditive = 0;
48030
48031 if ( weight < 1 ) {
48032
48033 // accuN := accuN + original * ( 1 - cumulativeWeight )
48034
48035 const originalValueOffset = stride * this._origIndex;
48036
48037 this._mixBufferRegion(
48038 buffer, offset, originalValueOffset, 1 - weight, stride );
48039
48040 }
48041
48042 if ( weightAdditive > 0 ) {
48043
48044 // accuN := accuN + additive accuN
48045
48046 this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
48047
48048 }
48049
48050 for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
48051
48052 if ( buffer[ i ] !== buffer[ i + stride ] ) {
48053
48054 // value has changed -> update scene graph
48055
48056 binding.setValue( buffer, offset );
48057 break;
48058
48059 }
48060
48061 }
48062
48063 }
48064
48065 // remember the state of the bound property and copy it to both accus
48066 saveOriginalState() {
48067
48068 const binding = this.binding;
48069
48070 const buffer = this.buffer,
48071 stride = this.valueSize,
48072
48073 originalValueOffset = stride * this._origIndex;
48074
48075 binding.getValue( buffer, originalValueOffset );
48076
48077 // accu[0..1] := orig -- initially detect changes against the original
48078 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {
48079
48080 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
48081
48082 }
48083
48084 // Add to identity for additive
48085 this._setIdentity();
48086
48087 this.cumulativeWeight = 0;
48088 this.cumulativeWeightAdditive = 0;
48089
48090 }
48091
48092 // apply the state previously taken via 'saveOriginalState' to the binding
48093 restoreOriginalState() {
48094
48095 const originalValueOffset = this.valueSize * 3;
48096 this.binding.setValue( this.buffer, originalValueOffset );
48097
48098 }
48099
48100 _setAdditiveIdentityNumeric() {
48101
48102 const startIndex = this._addIndex * this.valueSize;
48103 const endIndex = startIndex + this.valueSize;
48104
48105 for ( let i = startIndex; i < endIndex; i ++ ) {
48106
48107 this.buffer[ i ] = 0;
48108
48109 }
48110
48111 }
48112
48113 _setAdditiveIdentityQuaternion() {
48114
48115 this._setAdditiveIdentityNumeric();
48116 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
48117
48118 }
48119
48120 _setAdditiveIdentityOther() {
48121
48122 const startIndex = this._origIndex * this.valueSize;
48123 const targetIndex = this._addIndex * this.valueSize;
48124
48125 for ( let i = 0; i < this.valueSize; i ++ ) {
48126
48127 this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];
48128
48129 }
48130
48131 }
48132
48133
48134 // mix functions
48135
48136 _select( buffer, dstOffset, srcOffset, t, stride ) {
48137
48138 if ( t >= 0.5 ) {
48139
48140 for ( let i = 0; i !== stride; ++ i ) {
48141
48142 buffer[ dstOffset + i ] = buffer[ srcOffset + i ];
48143
48144 }
48145
48146 }
48147
48148 }
48149
48150 _slerp( buffer, dstOffset, srcOffset, t ) {
48151
48152 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );
48153
48154 }
48155
48156 _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48157
48158 const workOffset = this._workIndex * stride;
48159
48160 // Store result in intermediate buffer offset
48161 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
48162
48163 // Slerp to the intermediate result
48164 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
48165
48166 }
48167
48168 _lerp( buffer, dstOffset, srcOffset, t, stride ) {
48169
48170 const s = 1 - t;
48171
48172 for ( let i = 0; i !== stride; ++ i ) {
48173
48174 const j = dstOffset + i;
48175
48176 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;
48177
48178 }
48179
48180 }
48181
48182 _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {
48183
48184 for ( let i = 0; i !== stride; ++ i ) {
48185
48186 const j = dstOffset + i;
48187
48188 buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
48189
48190 }
48191
48192 }
48193
48194 }
48195
48196 // Characters [].:/ are reserved for track binding syntax.
48197 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/';
48198 const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );
48199
48200 // Attempts to allow node names from any language. ES5's `\w` regexp matches
48201 // only latin characters, and the unicode \p{L} is not yet supported. So
48202 // instead, we exclude reserved characters and match everything else.
48203 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
48204 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
48205
48206 // Parent directories, delimited by '/' or ':'. Currently unused, but must
48207 // be matched to parse the rest of the track name.
48208 const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar );
48209
48210 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
48211 const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
48212
48213 // Object on target node, and accessor. May not contain reserved
48214 // characters. Accessor may contain any character except closing bracket.
48215 const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar );
48216
48217 // Property and accessor. May not contain reserved characters. Accessor may
48218 // contain any non-bracket characters.
48219 const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar );
48220
48221 const _trackRe = new RegExp( ''
48222 + '^'
48223 + _directoryRe
48224 + _nodeRe
48225 + _objectRe
48226 + _propertyRe
48227 + '$'
48228 );
48229
48230 const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ];
48231
48232 class Composite {
48233
48234 constructor( targetGroup, path, optionalParsedPath ) {
48235
48236 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
48237
48238 this._targetGroup = targetGroup;
48239 this._bindings = targetGroup.subscribe_( path, parsedPath );
48240
48241 }
48242
48243 getValue( array, offset ) {
48244
48245 this.bind(); // bind all binding
48246
48247 const firstValidIndex = this._targetGroup.nCachedObjects_,
48248 binding = this._bindings[ firstValidIndex ];
48249
48250 // and only call .getValue on the first
48251 if ( binding !== undefined ) binding.getValue( array, offset );
48252
48253 }
48254
48255 setValue( array, offset ) {
48256
48257 const bindings = this._bindings;
48258
48259 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48260
48261 bindings[ i ].setValue( array, offset );
48262
48263 }
48264
48265 }
48266
48267 bind() {
48268
48269 const bindings = this._bindings;
48270
48271 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48272
48273 bindings[ i ].bind();
48274
48275 }
48276
48277 }
48278
48279 unbind() {
48280
48281 const bindings = this._bindings;
48282
48283 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {
48284
48285 bindings[ i ].unbind();
48286
48287 }
48288
48289 }
48290
48291 }
48292
48293 // Note: This class uses a State pattern on a per-method basis:
48294 // 'bind' sets 'this.getValue' / 'setValue' and shadows the
48295 // prototype version of these methods with one that represents
48296 // the bound state. When the property is not found, the methods
48297 // become no-ops.
48298 class PropertyBinding {
48299
48300 constructor( rootNode, path, parsedPath ) {
48301
48302 this.path = path;
48303 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
48304
48305 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName );
48306
48307 this.rootNode = rootNode;
48308
48309 // initial state of these methods that calls 'bind'
48310 this.getValue = this._getValue_unbound;
48311 this.setValue = this._setValue_unbound;
48312
48313 }
48314
48315
48316 static create( root, path, parsedPath ) {
48317
48318 if ( ! ( root && root.isAnimationObjectGroup ) ) {
48319
48320 return new PropertyBinding( root, path, parsedPath );
48321
48322 } else {
48323
48324 return new PropertyBinding.Composite( root, path, parsedPath );
48325
48326 }
48327
48328 }
48329
48337 static sanitizeNodeName( name ) {
48338
48339 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' );
48340
48341 }
48342
48343 static parseTrackName( trackName ) {
48344
48345 const matches = _trackRe.exec( trackName );
48346
48347 if ( matches === null ) {
48348
48349 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
48350
48351 }
48352
48353 const results = {
48354 // directoryName: matches[ 1 ], // (tschw) currently unused
48355 nodeName: matches[ 2 ],
48356 objectName: matches[ 3 ],
48357 objectIndex: matches[ 4 ],
48358 propertyName: matches[ 5 ], // required
48359 propertyIndex: matches[ 6 ]
48360 };
48361
48362 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
48363
48364 if ( lastDot !== undefined && lastDot !== - 1 ) {
48365
48366 const objectName = results.nodeName.substring( lastDot + 1 );
48367
48368 // Object names must be checked against an allowlist. Otherwise, there
48369 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but
48370 // 'bar' could be the objectName, or part of a nodeName (which can
48371 // include '.' characters).
48372 if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {
48373
48374 results.nodeName = results.nodeName.substring( 0, lastDot );
48375 results.objectName = objectName;
48376
48377 }
48378
48379 }
48380
48381 if ( results.propertyName === null || results.propertyName.length === 0 ) {
48382
48383 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
48384
48385 }
48386
48387 return results;
48388
48389 }
48390
48391 static findNode( root, nodeName ) {
48392
48393 if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {
48394
48395 return root;
48396
48397 }
48398
48399 // search into skeleton bones.
48400 if ( root.skeleton ) {
48401
48402 const bone = root.skeleton.getBoneByName( nodeName );
48403
48404 if ( bone !== undefined ) {
48405
48406 return bone;
48407
48408 }
48409
48410 }
48411
48412 // search into node subtree.
48413 if ( root.children ) {
48414
48415 const searchNodeSubtree = function ( children ) {
48416
48417 for ( let i = 0; i < children.length; i ++ ) {
48418
48419 const childNode = children[ i ];
48420
48421 if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
48422
48423 return childNode;
48424
48425 }
48426
48427 const result = searchNodeSubtree( childNode.children );
48428
48429 if ( result ) return result;
48430
48431 }
48432
48433 return null;
48434
48435 };
48436
48437 const subTreeNode = searchNodeSubtree( root.children );
48438
48439 if ( subTreeNode ) {
48440
48441 return subTreeNode;
48442
48443 }
48444
48445 }
48446
48447 return null;
48448
48449 }
48450
48451 // these are used to "bind" a nonexistent property
48452 _getValue_unavailable() {}
48453 _setValue_unavailable() {}
48454
48455 // Getters
48456
48457 _getValue_direct( buffer, offset ) {
48458
48459 buffer[ offset ] = this.targetObject[ this.propertyName ];
48460
48461 }
48462
48463 _getValue_array( buffer, offset ) {
48464
48465 const source = this.resolvedProperty;
48466
48467 for ( let i = 0, n = source.length; i !== n; ++ i ) {
48468
48469 buffer[ offset ++ ] = source[ i ];
48470
48471 }
48472
48473 }
48474
48475 _getValue_arrayElement( buffer, offset ) {
48476
48477 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];
48478
48479 }
48480
48481 _getValue_toArray( buffer, offset ) {
48482
48483 this.resolvedProperty.toArray( buffer, offset );
48484
48485 }
48486
48487 // Direct
48488
48489 _setValue_direct( buffer, offset ) {
48490
48491 this.targetObject[ this.propertyName ] = buffer[ offset ];
48492
48493 }
48494
48495 _setValue_direct_setNeedsUpdate( buffer, offset ) {
48496
48497 this.targetObject[ this.propertyName ] = buffer[ offset ];
48498 this.targetObject.needsUpdate = true;
48499
48500 }
48501
48502 _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {
48503
48504 this.targetObject[ this.propertyName ] = buffer[ offset ];
48505 this.targetObject.matrixWorldNeedsUpdate = true;
48506
48507 }
48508
48509 // EntireArray
48510
48511 _setValue_array( buffer, offset ) {
48512
48513 const dest = this.resolvedProperty;
48514
48515 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48516
48517 dest[ i ] = buffer[ offset ++ ];
48518
48519 }
48520
48521 }
48522
48523 _setValue_array_setNeedsUpdate( buffer, offset ) {
48524
48525 const dest = this.resolvedProperty;
48526
48527 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48528
48529 dest[ i ] = buffer[ offset ++ ];
48530
48531 }
48532
48533 this.targetObject.needsUpdate = true;
48534
48535 }
48536
48537 _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {
48538
48539 const dest = this.resolvedProperty;
48540
48541 for ( let i = 0, n = dest.length; i !== n; ++ i ) {
48542
48543 dest[ i ] = buffer[ offset ++ ];
48544
48545 }
48546
48547 this.targetObject.matrixWorldNeedsUpdate = true;
48548
48549 }
48550
48551 // ArrayElement
48552
48553 _setValue_arrayElement( buffer, offset ) {
48554
48555 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48556
48557 }
48558
48559 _setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
48560
48561 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48562 this.targetObject.needsUpdate = true;
48563
48564 }
48565
48566 _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {
48567
48568 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];
48569 this.targetObject.matrixWorldNeedsUpdate = true;
48570
48571 }
48572
48573 // HasToFromArray
48574
48575 _setValue_fromArray( buffer, offset ) {
48576
48577 this.resolvedProperty.fromArray( buffer, offset );
48578
48579 }
48580
48581 _setValue_fromArray_setNeedsUpdate( buffer, offset ) {
48582
48583 this.resolvedProperty.fromArray( buffer, offset );
48584 this.targetObject.needsUpdate = true;
48585
48586 }
48587
48588 _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {
48589
48590 this.resolvedProperty.fromArray( buffer, offset );
48591 this.targetObject.matrixWorldNeedsUpdate = true;
48592
48593 }
48594
48595 _getValue_unbound( targetArray, offset ) {
48596
48597 this.bind();
48598 this.getValue( targetArray, offset );
48599
48600 }
48601
48602 _setValue_unbound( sourceArray, offset ) {
48603
48604 this.bind();
48605 this.setValue( sourceArray, offset );
48606
48607 }
48608
48609 // create getter / setter pair for a property in the scene graph
48610 bind() {
48611
48612 let targetObject = this.node;
48613 const parsedPath = this.parsedPath;
48614
48615 const objectName = parsedPath.objectName;
48616 const propertyName = parsedPath.propertyName;
48617 let propertyIndex = parsedPath.propertyIndex;
48618
48619 if ( ! targetObject ) {
48620
48621 targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName );
48622
48623 this.node = targetObject;
48624
48625 }
48626
48627 // set fail state so we can just 'return' on error
48628 this.getValue = this._getValue_unavailable;
48629 this.setValue = this._setValue_unavailable;
48630
48631 // ensure there is a value node
48632 if ( ! targetObject ) {
48633
48634 console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' );
48635 return;
48636
48637 }
48638
48639 if ( objectName ) {
48640
48641 let objectIndex = parsedPath.objectIndex;
48642
48643 // special cases were we need to reach deeper into the hierarchy to get the face materials....
48644 switch ( objectName ) {
48645
48646 case 'materials':
48647
48648 if ( ! targetObject.material ) {
48649
48650 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48651 return;
48652
48653 }
48654
48655 if ( ! targetObject.material.materials ) {
48656
48657 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );
48658 return;
48659
48660 }
48661
48662 targetObject = targetObject.material.materials;
48663
48664 break;
48665
48666 case 'bones':
48667
48668 if ( ! targetObject.skeleton ) {
48669
48670 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );
48671 return;
48672
48673 }
48674
48675 // potential future optimization: skip this if propertyIndex is already an integer
48676 // and convert the integer string to a true integer.
48677
48678 targetObject = targetObject.skeleton.bones;
48679
48680 // support resolving morphTarget names into indices.
48681 for ( let i = 0; i < targetObject.length; i ++ ) {
48682
48683 if ( targetObject[ i ].name === objectIndex ) {
48684
48685 objectIndex = i;
48686 break;
48687
48688 }
48689
48690 }
48691
48692 break;
48693
48694 case 'map':
48695
48696 if ( 'map' in targetObject ) {
48697
48698 targetObject = targetObject.map;
48699 break;
48700
48701 }
48702
48703 if ( ! targetObject.material ) {
48704
48705 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );
48706 return;
48707
48708 }
48709
48710 if ( ! targetObject.material.map ) {
48711
48712 console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this );
48713 return;
48714
48715 }
48716
48717 targetObject = targetObject.material.map;
48718 break;
48719
48720 default:
48721
48722 if ( targetObject[ objectName ] === undefined ) {
48723
48724 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );
48725 return;
48726
48727 }
48728
48729 targetObject = targetObject[ objectName ];
48730
48731 }
48732
48733
48734 if ( objectIndex !== undefined ) {
48735
48736 if ( targetObject[ objectIndex ] === undefined ) {
48737
48738 console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );
48739 return;
48740
48741 }
48742
48743 targetObject = targetObject[ objectIndex ];
48744
48745 }
48746
48747 }
48748
48749 // resolve property
48750 const nodeProperty = targetObject[ propertyName ];
48751
48752 if ( nodeProperty === undefined ) {
48753
48754 const nodeName = parsedPath.nodeName;
48755
48756 console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +
48757 '.' + propertyName + ' but it wasn\'t found.', targetObject );
48758 return;
48759
48760 }
48761
48762 // determine versioning scheme
48763 let versioning = this.Versioning.None;
48764
48765 this.targetObject = targetObject;
48766
48767 if ( targetObject.needsUpdate !== undefined ) { // material
48768
48769 versioning = this.Versioning.NeedsUpdate;
48770
48771 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
48772
48773 versioning = this.Versioning.MatrixWorldNeedsUpdate;
48774
48775 }
48776
48777 // determine how the property gets bound
48778 let bindingType = this.BindingType.Direct;
48779
48780 if ( propertyIndex !== undefined ) {
48781
48782 // access a sub element of the property array (only primitives are supported right now)
48783
48784 if ( propertyName === 'morphTargetInfluences' ) {
48785
48786 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
48787
48788 // support resolving morphTarget names into indices.
48789 if ( ! targetObject.geometry ) {
48790
48791 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );
48792 return;
48793
48794 }
48795
48796 if ( ! targetObject.geometry.morphAttributes ) {
48797
48798 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );
48799 return;
48800
48801 }
48802
48803 if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {
48804
48805 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];
48806
48807 }
48808
48809 }
48810
48811 bindingType = this.BindingType.ArrayElement;
48812
48813 this.resolvedProperty = nodeProperty;
48814 this.propertyIndex = propertyIndex;
48815
48816 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
48817
48818 // must use copy for Object3D.Euler/Quaternion
48819
48820 bindingType = this.BindingType.HasFromToArray;
48821
48822 this.resolvedProperty = nodeProperty;
48823
48824 } else if ( Array.isArray( nodeProperty ) ) {
48825
48826 bindingType = this.BindingType.EntireArray;
48827
48828 this.resolvedProperty = nodeProperty;
48829
48830 } else {
48831
48832 this.propertyName = propertyName;
48833
48834 }
48835
48836 // select getter / setter
48837 this.getValue = this.GetterByBindingType[ bindingType ];
48838 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
48839
48840 }
48841
48842 unbind() {
48843
48844 this.node = null;
48845
48846 // back to the prototype version of getValue / setValue
48847 // note: avoiding to mutate the shape of 'this' via 'delete'
48848 this.getValue = this._getValue_unbound;
48849 this.setValue = this._setValue_unbound;
48850
48851 }
48852
48853 }
48854
48855 PropertyBinding.Composite = Composite;
48856
48857 PropertyBinding.prototype.BindingType = {
48858 Direct: 0,
48859 EntireArray: 1,
48860 ArrayElement: 2,
48861 HasFromToArray: 3
48862 };
48863
48864 PropertyBinding.prototype.Versioning = {
48865 None: 0,
48866 NeedsUpdate: 1,
48867 MatrixWorldNeedsUpdate: 2
48868 };
48869
48870 PropertyBinding.prototype.GetterByBindingType = [
48871
48872 PropertyBinding.prototype._getValue_direct,
48873 PropertyBinding.prototype._getValue_array,
48874 PropertyBinding.prototype._getValue_arrayElement,
48875 PropertyBinding.prototype._getValue_toArray,
48876
48877 ];
48878
48879 PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [
48880
48881 [
48882 // Direct
48883 PropertyBinding.prototype._setValue_direct,
48884 PropertyBinding.prototype._setValue_direct_setNeedsUpdate,
48885 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,
48886
48887 ], [
48888
48889 // EntireArray
48890
48891 PropertyBinding.prototype._setValue_array,
48892 PropertyBinding.prototype._setValue_array_setNeedsUpdate,
48893 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,
48894
48895 ], [
48896
48897 // ArrayElement
48898 PropertyBinding.prototype._setValue_arrayElement,
48899 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,
48900 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,
48901
48902 ], [
48903
48904 // HasToFromArray
48905 PropertyBinding.prototype._setValue_fromArray,
48906 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,
48907 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,
48908
48909 ]
48910
48911 ];
48912
48942 class AnimationObjectGroup {
48943
48944 constructor() {
48945
48946 this.isAnimationObjectGroup = true;
48947
48948 this.uuid = generateUUID();
48949
48950 // cached objects followed by the active ones
48951 this._objects = Array.prototype.slice.call( arguments );
48952
48953 this.nCachedObjects_ = 0; // threshold
48954 // note: read by PropertyBinding.Composite
48955
48956 const indices = {};
48957 this._indicesByUUID = indices; // for bookkeeping
48958
48959 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
48960
48961 indices[ arguments[ i ].uuid ] = i;
48962
48963 }
48964
48965 this._paths = []; // inside: string
48966 this._parsedPaths = []; // inside: { we don't care, here }
48967 this._bindings = []; // inside: Array< PropertyBinding >
48968 this._bindingsIndicesByPath = {}; // inside: indices in these arrays
48969
48970 const scope = this;
48971
48972 this.stats = {
48973
48974 objects: {
48975 get total() {
48976
48977 return scope._objects.length;
48978
48979 },
48980 get inUse() {
48981
48982 return this.total - scope.nCachedObjects_;
48983
48984 }
48985 },
48986 get bindingsPerObject() {
48987
48988 return scope._bindings.length;
48989
48990 }
48991
48992 };
48993
48994 }
48995
48996 add() {
48997
48998 const objects = this._objects,
48999 indicesByUUID = this._indicesByUUID,
49000 paths = this._paths,
49001 parsedPaths = this._parsedPaths,
49002 bindings = this._bindings,
49003 nBindings = bindings.length;
49004
49005 let knownObject = undefined,
49006 nObjects = objects.length,
49007 nCachedObjects = this.nCachedObjects_;
49008
49009 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49010
49011 const object = arguments[ i ],
49012 uuid = object.uuid;
49013 let index = indicesByUUID[ uuid ];
49014
49015 if ( index === undefined ) {
49016
49017 // unknown object -> add it to the ACTIVE region
49018
49019 index = nObjects ++;
49020 indicesByUUID[ uuid ] = index;
49021 objects.push( object );
49022
49023 // accounting is done, now do the same for all bindings
49024
49025 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49026
49027 bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );
49028
49029 }
49030
49031 } else if ( index < nCachedObjects ) {
49032
49033 knownObject = objects[ index ];
49034
49035 // move existing object to the ACTIVE region
49036
49037 const firstActiveIndex = -- nCachedObjects,
49038 lastCachedObject = objects[ firstActiveIndex ];
49039
49040 indicesByUUID[ lastCachedObject.uuid ] = index;
49041 objects[ index ] = lastCachedObject;
49042
49043 indicesByUUID[ uuid ] = firstActiveIndex;
49044 objects[ firstActiveIndex ] = object;
49045
49046 // accounting is done, now do the same for all bindings
49047
49048 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49049
49050 const bindingsForPath = bindings[ j ],
49051 lastCached = bindingsForPath[ firstActiveIndex ];
49052
49053 let binding = bindingsForPath[ index ];
49054
49055 bindingsForPath[ index ] = lastCached;
49056
49057 if ( binding === undefined ) {
49058
49059 // since we do not bother to create new bindings
49060 // for objects that are cached, the binding may
49061 // or may not exist
49062
49063 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );
49064
49065 }
49066
49067 bindingsForPath[ firstActiveIndex ] = binding;
49068
49069 }
49070
49071 } else if ( objects[ index ] !== knownObject ) {
49072
49073 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +
49074 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );
49075
49076 } // else the object is already where we want it to be
49077
49078 } // for arguments
49079
49080 this.nCachedObjects_ = nCachedObjects;
49081
49082 }
49083
49084 remove() {
49085
49086 const objects = this._objects,
49087 indicesByUUID = this._indicesByUUID,
49088 bindings = this._bindings,
49089 nBindings = bindings.length;
49090
49091 let nCachedObjects = this.nCachedObjects_;
49092
49093 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49094
49095 const object = arguments[ i ],
49096 uuid = object.uuid,
49097 index = indicesByUUID[ uuid ];
49098
49099 if ( index !== undefined && index >= nCachedObjects ) {
49100
49101 // move existing object into the CACHED region
49102
49103 const lastCachedIndex = nCachedObjects ++,
49104 firstActiveObject = objects[ lastCachedIndex ];
49105
49106 indicesByUUID[ firstActiveObject.uuid ] = index;
49107 objects[ index ] = firstActiveObject;
49108
49109 indicesByUUID[ uuid ] = lastCachedIndex;
49110 objects[ lastCachedIndex ] = object;
49111
49112 // accounting is done, now do the same for all bindings
49113
49114 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49115
49116 const bindingsForPath = bindings[ j ],
49117 firstActive = bindingsForPath[ lastCachedIndex ],
49118 binding = bindingsForPath[ index ];
49119
49120 bindingsForPath[ index ] = firstActive;
49121 bindingsForPath[ lastCachedIndex ] = binding;
49122
49123 }
49124
49125 }
49126
49127 } // for arguments
49128
49129 this.nCachedObjects_ = nCachedObjects;
49130
49131 }
49132
49133 // remove & forget
49134 uncache() {
49135
49136 const objects = this._objects,
49137 indicesByUUID = this._indicesByUUID,
49138 bindings = this._bindings,
49139 nBindings = bindings.length;
49140
49141 let nCachedObjects = this.nCachedObjects_,
49142 nObjects = objects.length;
49143
49144 for ( let i = 0, n = arguments.length; i !== n; ++ i ) {
49145
49146 const object = arguments[ i ],
49147 uuid = object.uuid,
49148 index = indicesByUUID[ uuid ];
49149
49150 if ( index !== undefined ) {
49151
49152 delete indicesByUUID[ uuid ];
49153
49154 if ( index < nCachedObjects ) {
49155
49156 // object is cached, shrink the CACHED region
49157
49158 const firstActiveIndex = -- nCachedObjects,
49159 lastCachedObject = objects[ firstActiveIndex ],
49160 lastIndex = -- nObjects,
49161 lastObject = objects[ lastIndex ];
49162
49163 // last cached object takes this object's place
49164 indicesByUUID[ lastCachedObject.uuid ] = index;
49165 objects[ index ] = lastCachedObject;
49166
49167 // last object goes to the activated slot and pop
49168 indicesByUUID[ lastObject.uuid ] = firstActiveIndex;
49169 objects[ firstActiveIndex ] = lastObject;
49170 objects.pop();
49171
49172 // accounting is done, now do the same for all bindings
49173
49174 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49175
49176 const bindingsForPath = bindings[ j ],
49177 lastCached = bindingsForPath[ firstActiveIndex ],
49178 last = bindingsForPath[ lastIndex ];
49179
49180 bindingsForPath[ index ] = lastCached;
49181 bindingsForPath[ firstActiveIndex ] = last;
49182 bindingsForPath.pop();
49183
49184 }
49185
49186 } else {
49187
49188 // object is active, just swap with the last and pop
49189
49190 const lastIndex = -- nObjects,
49191 lastObject = objects[ lastIndex ];
49192
49193 if ( lastIndex > 0 ) {
49194
49195 indicesByUUID[ lastObject.uuid ] = index;
49196
49197 }
49198
49199 objects[ index ] = lastObject;
49200 objects.pop();
49201
49202 // accounting is done, now do the same for all bindings
49203
49204 for ( let j = 0, m = nBindings; j !== m; ++ j ) {
49205
49206 const bindingsForPath = bindings[ j ];
49207
49208 bindingsForPath[ index ] = bindingsForPath[ lastIndex ];
49209 bindingsForPath.pop();
49210
49211 }
49212
49213 } // cached or active
49214
49215 } // if object is known
49216
49217 } // for arguments
49218
49219 this.nCachedObjects_ = nCachedObjects;
49220
49221 }
49222
49223 // Internal interface used by befriended PropertyBinding.Composite:
49224
49225 subscribe_( path, parsedPath ) {
49226
49227 // returns an array of bindings for the given path that is changed
49228 // according to the contained objects in the group
49229
49230 const indicesByPath = this._bindingsIndicesByPath;
49231 let index = indicesByPath[ path ];
49232 const bindings = this._bindings;
49233
49234 if ( index !== undefined ) return bindings[ index ];
49235
49236 const paths = this._paths,
49237 parsedPaths = this._parsedPaths,
49238 objects = this._objects,
49239 nObjects = objects.length,
49240 nCachedObjects = this.nCachedObjects_,
49241 bindingsForPath = new Array( nObjects );
49242
49243 index = bindings.length;
49244
49245 indicesByPath[ path ] = index;
49246
49247 paths.push( path );
49248 parsedPaths.push( parsedPath );
49249 bindings.push( bindingsForPath );
49250
49251 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {
49252
49253 const object = objects[ i ];
49254 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );
49255
49256 }
49257
49258 return bindingsForPath;
49259
49260 }
49261
49262 unsubscribe_( path ) {
49263
49264 // tells the group to forget about a property path and no longer
49265 // update the array previously obtained with 'subscribe_'
49266
49267 const indicesByPath = this._bindingsIndicesByPath,
49268 index = indicesByPath[ path ];
49269
49270 if ( index !== undefined ) {
49271
49272 const paths = this._paths,
49273 parsedPaths = this._parsedPaths,
49274 bindings = this._bindings,
49275 lastBindingsIndex = bindings.length - 1,
49276 lastBindings = bindings[ lastBindingsIndex ],
49277 lastBindingsPath = path[ lastBindingsIndex ];
49278
49279 indicesByPath[ lastBindingsPath ] = index;
49280
49281 bindings[ index ] = lastBindings;
49282 bindings.pop();
49283
49284 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];
49285 parsedPaths.pop();
49286
49287 paths[ index ] = paths[ lastBindingsIndex ];
49288 paths.pop();
49289
49290 }
49291
49292 }
49293
49294 }
49295
49296 class AnimationAction {
49297
49298 constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {
49299
49300 this._mixer = mixer;
49301 this._clip = clip;
49302 this._localRoot = localRoot;
49303 this.blendMode = blendMode;
49304
49305 const tracks = clip.tracks,
49306 nTracks = tracks.length,
49307 interpolants = new Array( nTracks );
49308
49309 const interpolantSettings = {
49310 endingStart: ZeroCurvatureEnding,
49311 endingEnd: ZeroCurvatureEnding
49312 };
49313
49314 for ( let i = 0; i !== nTracks; ++ i ) {
49315
49316 const interpolant = tracks[ i ].createInterpolant( null );
49317 interpolants[ i ] = interpolant;
49318 interpolant.settings = interpolantSettings;
49319
49320 }
49321
49322 this._interpolantSettings = interpolantSettings;
49323
49324 this._interpolants = interpolants; // bound by the mixer
49325
49326 // inside: PropertyMixer (managed by the mixer)
49327 this._propertyBindings = new Array( nTracks );
49328
49329 this._cacheIndex = null; // for the memory manager
49330 this._byClipCacheIndex = null; // for the memory manager
49331
49332 this._timeScaleInterpolant = null;
49333 this._weightInterpolant = null;
49334
49335 this.loop = LoopRepeat;
49336 this._loopCount = - 1;
49337
49338 // global mixer time when the action is to be started
49339 // it's set back to 'null' upon start of the action
49340 this._startTime = null;
49341
49342 // scaled local time of the action
49343 // gets clamped or wrapped to 0..clip.duration according to loop
49344 this.time = 0;
49345
49346 this.timeScale = 1;
49347 this._effectiveTimeScale = 1;
49348
49349 this.weight = 1;
49350 this._effectiveWeight = 1;
49351
49352 this.repetitions = Infinity; // no. of repetitions when looping
49353
49354 this.paused = false; // true -> zero effective time scale
49355 this.enabled = true; // false -> zero effective weight
49356
49357 this.clampWhenFinished = false;// keep feeding the last frame?
49358
49359 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
49360 this.zeroSlopeAtEnd = true;// clips for start, loop and end
49361
49362 }
49363
49364 // State & Scheduling
49365
49366 play() {
49367
49368 this._mixer._activateAction( this );
49369
49370 return this;
49371
49372 }
49373
49374 stop() {
49375
49376 this._mixer._deactivateAction( this );
49377
49378 return this.reset();
49379
49380 }
49381
49382 reset() {
49383
49384 this.paused = false;
49385 this.enabled = true;
49386
49387 this.time = 0; // restart clip
49388 this._loopCount = - 1;// forget previous loops
49389 this._startTime = null;// forget scheduling
49390
49391 return this.stopFading().stopWarping();
49392
49393 }
49394
49395 isRunning() {
49396
49397 return this.enabled && ! this.paused && this.timeScale !== 0 &&
49398 this._startTime === null && this._mixer._isActiveAction( this );
49399
49400 }
49401
49402 // return true when play has been called
49403 isScheduled() {
49404
49405 return this._mixer._isActiveAction( this );
49406
49407 }
49408
49409 startAt( time ) {
49410
49411 this._startTime = time;
49412
49413 return this;
49414
49415 }
49416
49417 setLoop( mode, repetitions ) {
49418
49419 this.loop = mode;
49420 this.repetitions = repetitions;
49421
49422 return this;
49423
49424 }
49425
49426 // Weight
49427
49428 // set the weight stopping any scheduled fading
49429 // although .enabled = false yields an effective weight of zero, this
49430 // method does *not* change .enabled, because it would be confusing
49431 setEffectiveWeight( weight ) {
49432
49433 this.weight = weight;
49434
49435 // note: same logic as when updated at runtime
49436 this._effectiveWeight = this.enabled ? weight : 0;
49437
49438 return this.stopFading();
49439
49440 }
49441
49442 // return the weight considering fading and .enabled
49443 getEffectiveWeight() {
49444
49445 return this._effectiveWeight;
49446
49447 }
49448
49449 fadeIn( duration ) {
49450
49451 return this._scheduleFading( duration, 0, 1 );
49452
49453 }
49454
49455 fadeOut( duration ) {
49456
49457 return this._scheduleFading( duration, 1, 0 );
49458
49459 }
49460
49461 crossFadeFrom( fadeOutAction, duration, warp ) {
49462
49463 fadeOutAction.fadeOut( duration );
49464 this.fadeIn( duration );
49465
49466 if ( warp ) {
49467
49468 const fadeInDuration = this._clip.duration,
49469 fadeOutDuration = fadeOutAction._clip.duration,
49470
49471 startEndRatio = fadeOutDuration / fadeInDuration,
49472 endStartRatio = fadeInDuration / fadeOutDuration;
49473
49474 fadeOutAction.warp( 1.0, startEndRatio, duration );
49475 this.warp( endStartRatio, 1.0, duration );
49476
49477 }
49478
49479 return this;
49480
49481 }
49482
49483 crossFadeTo( fadeInAction, duration, warp ) {
49484
49485 return fadeInAction.crossFadeFrom( this, duration, warp );
49486
49487 }
49488
49489 stopFading() {
49490
49491 const weightInterpolant = this._weightInterpolant;
49492
49493 if ( weightInterpolant !== null ) {
49494
49495 this._weightInterpolant = null;
49496 this._mixer._takeBackControlInterpolant( weightInterpolant );
49497
49498 }
49499
49500 return this;
49501
49502 }
49503
49504 // Time Scale Control
49505
49506 // set the time scale stopping any scheduled warping
49507 // although .paused = true yields an effective time scale of zero, this
49508 // method does *not* change .paused, because it would be confusing
49509 setEffectiveTimeScale( timeScale ) {
49510
49511 this.timeScale = timeScale;
49512 this._effectiveTimeScale = this.paused ? 0 : timeScale;
49513
49514 return this.stopWarping();
49515
49516 }
49517
49518 // return the time scale considering warping and .paused
49519 getEffectiveTimeScale() {
49520
49521 return this._effectiveTimeScale;
49522
49523 }
49524
49525 setDuration( duration ) {
49526
49527 this.timeScale = this._clip.duration / duration;
49528
49529 return this.stopWarping();
49530
49531 }
49532
49533 syncWith( action ) {
49534
49535 this.time = action.time;
49536 this.timeScale = action.timeScale;
49537
49538 return this.stopWarping();
49539
49540 }
49541
49542 halt( duration ) {
49543
49544 return this.warp( this._effectiveTimeScale, 0, duration );
49545
49546 }
49547
49548 warp( startTimeScale, endTimeScale, duration ) {
49549
49550 const mixer = this._mixer,
49551 now = mixer.time,
49552 timeScale = this.timeScale;
49553
49554 let interpolant = this._timeScaleInterpolant;
49555
49556 if ( interpolant === null ) {
49557
49558 interpolant = mixer._lendControlInterpolant();
49559 this._timeScaleInterpolant = interpolant;
49560
49561 }
49562
49563 const times = interpolant.parameterPositions,
49564 values = interpolant.sampleValues;
49565
49566 times[ 0 ] = now;
49567 times[ 1 ] = now + duration;
49568
49569 values[ 0 ] = startTimeScale / timeScale;
49570 values[ 1 ] = endTimeScale / timeScale;
49571
49572 return this;
49573
49574 }
49575
49576 stopWarping() {
49577
49578 const timeScaleInterpolant = this._timeScaleInterpolant;
49579
49580 if ( timeScaleInterpolant !== null ) {
49581
49582 this._timeScaleInterpolant = null;
49583 this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
49584
49585 }
49586
49587 return this;
49588
49589 }
49590
49591 // Object Accessors
49592
49593 getMixer() {
49594
49595 return this._mixer;
49596
49597 }
49598
49599 getClip() {
49600
49601 return this._clip;
49602
49603 }
49604
49605 getRoot() {
49606
49607 return this._localRoot || this._mixer._root;
49608
49609 }
49610
49611 // Interna
49612
49613 _update( time, deltaTime, timeDirection, accuIndex ) {
49614
49615 // called by the mixer
49616
49617 if ( ! this.enabled ) {
49618
49619 // call ._updateWeight() to update ._effectiveWeight
49620
49621 this._updateWeight( time );
49622 return;
49623
49624 }
49625
49626 const startTime = this._startTime;
49627
49628 if ( startTime !== null ) {
49629
49630 // check for scheduled start of action
49631
49632 const timeRunning = ( time - startTime ) * timeDirection;
49633 if ( timeRunning < 0 || timeDirection === 0 ) {
49634
49635 deltaTime = 0;
49636
49637 } else {
49638
49639
49640 this._startTime = null; // unschedule
49641 deltaTime = timeDirection * timeRunning;
49642
49643 }
49644
49645 }
49646
49647 // apply time scale and advance time
49648
49649 deltaTime *= this._updateTimeScale( time );
49650 const clipTime = this._updateTime( deltaTime );
49651
49652 // note: _updateTime may disable the action resulting in
49653 // an effective weight of 0
49654
49655 const weight = this._updateWeight( time );
49656
49657 if ( weight > 0 ) {
49658
49659 const interpolants = this._interpolants;
49660 const propertyMixers = this._propertyBindings;
49661
49662 switch ( this.blendMode ) {
49663
49664 case AdditiveAnimationBlendMode:
49665
49666 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49667
49668 interpolants[ j ].evaluate( clipTime );
49669 propertyMixers[ j ].accumulateAdditive( weight );
49670
49671 }
49672
49673 break;
49674
49675 case NormalAnimationBlendMode:
49676 default:
49677
49678 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) {
49679
49680 interpolants[ j ].evaluate( clipTime );
49681 propertyMixers[ j ].accumulate( accuIndex, weight );
49682
49683 }
49684
49685 }
49686
49687 }
49688
49689 }
49690
49691 _updateWeight( time ) {
49692
49693 let weight = 0;
49694
49695 if ( this.enabled ) {
49696
49697 weight = this.weight;
49698 const interpolant = this._weightInterpolant;
49699
49700 if ( interpolant !== null ) {
49701
49702 const interpolantValue = interpolant.evaluate( time )[ 0 ];
49703
49704 weight *= interpolantValue;
49705
49706 if ( time > interpolant.parameterPositions[ 1 ] ) {
49707
49708 this.stopFading();
49709
49710 if ( interpolantValue === 0 ) {
49711
49712 // faded out, disable
49713 this.enabled = false;
49714
49715 }
49716
49717 }
49718
49719 }
49720
49721 }
49722
49723 this._effectiveWeight = weight;
49724 return weight;
49725
49726 }
49727
49728 _updateTimeScale( time ) {
49729
49730 let timeScale = 0;
49731
49732 if ( ! this.paused ) {
49733
49734 timeScale = this.timeScale;
49735
49736 const interpolant = this._timeScaleInterpolant;
49737
49738 if ( interpolant !== null ) {
49739
49740 const interpolantValue = interpolant.evaluate( time )[ 0 ];
49741
49742 timeScale *= interpolantValue;
49743
49744 if ( time > interpolant.parameterPositions[ 1 ] ) {
49745
49746 this.stopWarping();
49747
49748 if ( timeScale === 0 ) {
49749
49750 // motion has halted, pause
49751 this.paused = true;
49752
49753 } else {
49754
49755 // warp done - apply final time scale
49756 this.timeScale = timeScale;
49757
49758 }
49759
49760 }
49761
49762 }
49763
49764 }
49765
49766 this._effectiveTimeScale = timeScale;
49767 return timeScale;
49768
49769 }
49770
49771 _updateTime( deltaTime ) {
49772
49773 const duration = this._clip.duration;
49774 const loop = this.loop;
49775
49776 let time = this.time + deltaTime;
49777 let loopCount = this._loopCount;
49778
49779 const pingPong = ( loop === LoopPingPong );
49780
49781 if ( deltaTime === 0 ) {
49782
49783 if ( loopCount === - 1 ) return time;
49784
49785 return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;
49786
49787 }
49788
49789 if ( loop === LoopOnce ) {
49790
49791 if ( loopCount === - 1 ) {
49792
49793 // just started
49794
49795 this._loopCount = 0;
49796 this._setEndings( true, true, false );
49797
49798 }
49799
49800 handle_stop: {
49801
49802 if ( time >= duration ) {
49803
49804 time = duration;
49805
49806 } else if ( time < 0 ) {
49807
49808 time = 0;
49809
49810 } else {
49811
49812 this.time = time;
49813
49814 break handle_stop;
49815
49816 }
49817
49818 if ( this.clampWhenFinished ) this.paused = true;
49819 else this.enabled = false;
49820
49821 this.time = time;
49822
49823 this._mixer.dispatchEvent( {
49824 type: 'finished', action: this,
49825 direction: deltaTime < 0 ? - 1 : 1
49826 } );
49827
49828 }
49829
49830 } else { // repetitive Repeat or PingPong
49831
49832 if ( loopCount === - 1 ) {
49833
49834 // just started
49835
49836 if ( deltaTime >= 0 ) {
49837
49838 loopCount = 0;
49839
49840 this._setEndings( true, this.repetitions === 0, pingPong );
49841
49842 } else {
49843
49844 // when looping in reverse direction, the initial
49845 // transition through zero counts as a repetition,
49846 // so leave loopCount at -1
49847
49848 this._setEndings( this.repetitions === 0, true, pingPong );
49849
49850 }
49851
49852 }
49853
49854 if ( time >= duration || time < 0 ) {
49855
49856 // wrap around
49857
49858 const loopDelta = Math.floor( time / duration ); // signed
49859 time -= duration * loopDelta;
49860
49861 loopCount += Math.abs( loopDelta );
49862
49863 const pending = this.repetitions - loopCount;
49864
49865 if ( pending <= 0 ) {
49866
49867 // have to stop (switch state, clamp time, fire event)
49868
49869 if ( this.clampWhenFinished ) this.paused = true;
49870 else this.enabled = false;
49871
49872 time = deltaTime > 0 ? duration : 0;
49873
49874 this.time = time;
49875
49876 this._mixer.dispatchEvent( {
49877 type: 'finished', action: this,
49878 direction: deltaTime > 0 ? 1 : - 1
49879 } );
49880
49881 } else {
49882
49883 // keep running
49884
49885 if ( pending === 1 ) {
49886
49887 // entering the last round
49888
49889 const atStart = deltaTime < 0;
49890 this._setEndings( atStart, ! atStart, pingPong );
49891
49892 } else {
49893
49894 this._setEndings( false, false, pingPong );
49895
49896 }
49897
49898 this._loopCount = loopCount;
49899
49900 this.time = time;
49901
49902 this._mixer.dispatchEvent( {
49903 type: 'loop', action: this, loopDelta: loopDelta
49904 } );
49905
49906 }
49907
49908 } else {
49909
49910 this.time = time;
49911
49912 }
49913
49914 if ( pingPong && ( loopCount & 1 ) === 1 ) {
49915
49916 // invert time for the "pong round"
49917
49918 return duration - time;
49919
49920 }
49921
49922 }
49923
49924 return time;
49925
49926 }
49927
49928 _setEndings( atStart, atEnd, pingPong ) {
49929
49930 const settings = this._interpolantSettings;
49931
49932 if ( pingPong ) {
49933
49934 settings.endingStart = ZeroSlopeEnding;
49935 settings.endingEnd = ZeroSlopeEnding;
49936
49937 } else {
49938
49939 // assuming for LoopOnce atStart == atEnd == true
49940
49941 if ( atStart ) {
49942
49943 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;
49944
49945 } else {
49946
49947 settings.endingStart = WrapAroundEnding;
49948
49949 }
49950
49951 if ( atEnd ) {
49952
49953 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;
49954
49955 } else {
49956
49957 settings.endingEnd = WrapAroundEnding;
49958
49959 }
49960
49961 }
49962
49963 }
49964
49965 _scheduleFading( duration, weightNow, weightThen ) {
49966
49967 const mixer = this._mixer, now = mixer.time;
49968 let interpolant = this._weightInterpolant;
49969
49970 if ( interpolant === null ) {
49971
49972 interpolant = mixer._lendControlInterpolant();
49973 this._weightInterpolant = interpolant;
49974
49975 }
49976
49977 const times = interpolant.parameterPositions,
49978 values = interpolant.sampleValues;
49979
49980 times[ 0 ] = now;
49981 values[ 0 ] = weightNow;
49982 times[ 1 ] = now + duration;
49983 values[ 1 ] = weightThen;
49984
49985 return this;
49986
49987 }
49988
49989 }
49990
49991 const _controlInterpolantsResultBuffer = new Float32Array( 1 );
49992
49993
49994 class AnimationMixer extends EventDispatcher {
49995
49996 constructor( root ) {
49997
49998 super();
49999
50000 this._root = root;
50001 this._initMemoryManager();
50002 this._accuIndex = 0;
50003 this.time = 0;
50004 this.timeScale = 1.0;
50005
50006 }
50007
50008 _bindAction( action, prototypeAction ) {
50009
50010 const root = action._localRoot || this._root,
50011 tracks = action._clip.tracks,
50012 nTracks = tracks.length,
50013 bindings = action._propertyBindings,
50014 interpolants = action._interpolants,
50015 rootUuid = root.uuid,
50016 bindingsByRoot = this._bindingsByRootAndName;
50017
50018 let bindingsByName = bindingsByRoot[ rootUuid ];
50019
50020 if ( bindingsByName === undefined ) {
50021
50022 bindingsByName = {};
50023 bindingsByRoot[ rootUuid ] = bindingsByName;
50024
50025 }
50026
50027 for ( let i = 0; i !== nTracks; ++ i ) {
50028
50029 const track = tracks[ i ],
50030 trackName = track.name;
50031
50032 let binding = bindingsByName[ trackName ];
50033
50034 if ( binding !== undefined ) {
50035
50036 ++ binding.referenceCount;
50037 bindings[ i ] = binding;
50038
50039 } else {
50040
50041 binding = bindings[ i ];
50042
50043 if ( binding !== undefined ) {
50044
50045 // existing binding, make sure the cache knows
50046
50047 if ( binding._cacheIndex === null ) {
50048
50049 ++ binding.referenceCount;
50050 this._addInactiveBinding( binding, rootUuid, trackName );
50051
50052 }
50053
50054 continue;
50055
50056 }
50057
50058 const path = prototypeAction && prototypeAction.
50059 _propertyBindings[ i ].binding.parsedPath;
50060
50061 binding = new PropertyMixer(
50062 PropertyBinding.create( root, trackName, path ),
50063 track.ValueTypeName, track.getValueSize() );
50064
50065 ++ binding.referenceCount;
50066 this._addInactiveBinding( binding, rootUuid, trackName );
50067
50068 bindings[ i ] = binding;
50069
50070 }
50071
50072 interpolants[ i ].resultBuffer = binding.buffer;
50073
50074 }
50075
50076 }
50077
50078 _activateAction( action ) {
50079
50080 if ( ! this._isActiveAction( action ) ) {
50081
50082 if ( action._cacheIndex === null ) {
50083
50084 // this action has been forgotten by the cache, but the user
50085 // appears to be still using it -> rebind
50086
50087 const rootUuid = ( action._localRoot || this._root ).uuid,
50088 clipUuid = action._clip.uuid,
50089 actionsForClip = this._actionsByClip[ clipUuid ];
50090
50091 this._bindAction( action,
50092 actionsForClip && actionsForClip.knownActions[ 0 ] );
50093
50094 this._addInactiveAction( action, clipUuid, rootUuid );
50095
50096 }
50097
50098 const bindings = action._propertyBindings;
50099
50100 // increment reference counts / sort out state
50101 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50102
50103 const binding = bindings[ i ];
50104
50105 if ( binding.useCount ++ === 0 ) {
50106
50107 this._lendBinding( binding );
50108 binding.saveOriginalState();
50109
50110 }
50111
50112 }
50113
50114 this._lendAction( action );
50115
50116 }
50117
50118 }
50119
50120 _deactivateAction( action ) {
50121
50122 if ( this._isActiveAction( action ) ) {
50123
50124 const bindings = action._propertyBindings;
50125
50126 // decrement reference counts / sort out state
50127 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50128
50129 const binding = bindings[ i ];
50130
50131 if ( -- binding.useCount === 0 ) {
50132
50133 binding.restoreOriginalState();
50134 this._takeBackBinding( binding );
50135
50136 }
50137
50138 }
50139
50140 this._takeBackAction( action );
50141
50142 }
50143
50144 }
50145
50146 // Memory manager
50147
50148 _initMemoryManager() {
50149
50150 this._actions = []; // 'nActiveActions' followed by inactive ones
50151 this._nActiveActions = 0;
50152
50153 this._actionsByClip = {};
50154 // inside:
50155 // {
50156 // knownActions: Array< AnimationAction > - used as prototypes
50157 // actionByRoot: AnimationAction - lookup
50158 // }
50159
50160
50161 this._bindings = []; // 'nActiveBindings' followed by inactive ones
50162 this._nActiveBindings = 0;
50163
50164 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >
50165
50166
50167 this._controlInterpolants = []; // same game as above
50168 this._nActiveControlInterpolants = 0;
50169
50170 const scope = this;
50171
50172 this.stats = {
50173
50174 actions: {
50175 get total() {
50176
50177 return scope._actions.length;
50178
50179 },
50180 get inUse() {
50181
50182 return scope._nActiveActions;
50183
50184 }
50185 },
50186 bindings: {
50187 get total() {
50188
50189 return scope._bindings.length;
50190
50191 },
50192 get inUse() {
50193
50194 return scope._nActiveBindings;
50195
50196 }
50197 },
50198 controlInterpolants: {
50199 get total() {
50200
50201 return scope._controlInterpolants.length;
50202
50203 },
50204 get inUse() {
50205
50206 return scope._nActiveControlInterpolants;
50207
50208 }
50209 }
50210
50211 };
50212
50213 }
50214
50215 // Memory management for AnimationAction objects
50216
50217 _isActiveAction( action ) {
50218
50219 const index = action._cacheIndex;
50220 return index !== null && index < this._nActiveActions;
50221
50222 }
50223
50224 _addInactiveAction( action, clipUuid, rootUuid ) {
50225
50226 const actions = this._actions,
50227 actionsByClip = this._actionsByClip;
50228
50229 let actionsForClip = actionsByClip[ clipUuid ];
50230
50231 if ( actionsForClip === undefined ) {
50232
50233 actionsForClip = {
50234
50235 knownActions: [ action ],
50236 actionByRoot: {}
50237
50238 };
50239
50240 action._byClipCacheIndex = 0;
50241
50242 actionsByClip[ clipUuid ] = actionsForClip;
50243
50244 } else {
50245
50246 const knownActions = actionsForClip.knownActions;
50247
50248 action._byClipCacheIndex = knownActions.length;
50249 knownActions.push( action );
50250
50251 }
50252
50253 action._cacheIndex = actions.length;
50254 actions.push( action );
50255
50256 actionsForClip.actionByRoot[ rootUuid ] = action;
50257
50258 }
50259
50260 _removeInactiveAction( action ) {
50261
50262 const actions = this._actions,
50263 lastInactiveAction = actions[ actions.length - 1 ],
50264 cacheIndex = action._cacheIndex;
50265
50266 lastInactiveAction._cacheIndex = cacheIndex;
50267 actions[ cacheIndex ] = lastInactiveAction;
50268 actions.pop();
50269
50270 action._cacheIndex = null;
50271
50272
50273 const clipUuid = action._clip.uuid,
50274 actionsByClip = this._actionsByClip,
50275 actionsForClip = actionsByClip[ clipUuid ],
50276 knownActionsForClip = actionsForClip.knownActions,
50277
50278 lastKnownAction =
50279 knownActionsForClip[ knownActionsForClip.length - 1 ],
50280
50281 byClipCacheIndex = action._byClipCacheIndex;
50282
50283 lastKnownAction._byClipCacheIndex = byClipCacheIndex;
50284 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
50285 knownActionsForClip.pop();
50286
50287 action._byClipCacheIndex = null;
50288
50289
50290 const actionByRoot = actionsForClip.actionByRoot,
50291 rootUuid = ( action._localRoot || this._root ).uuid;
50292
50293 delete actionByRoot[ rootUuid ];
50294
50295 if ( knownActionsForClip.length === 0 ) {
50296
50297 delete actionsByClip[ clipUuid ];
50298
50299 }
50300
50301 this._removeInactiveBindingsForAction( action );
50302
50303 }
50304
50305 _removeInactiveBindingsForAction( action ) {
50306
50307 const bindings = action._propertyBindings;
50308
50309 for ( let i = 0, n = bindings.length; i !== n; ++ i ) {
50310
50311 const binding = bindings[ i ];
50312
50313 if ( -- binding.referenceCount === 0 ) {
50314
50315 this._removeInactiveBinding( binding );
50316
50317 }
50318
50319 }
50320
50321 }
50322
50323 _lendAction( action ) {
50324
50325 // [ active actions | inactive actions ]
50326 // [ active actions >| inactive actions ]
50327 // s a
50328 // <-swap->
50329 // a s
50330
50331 const actions = this._actions,
50332 prevIndex = action._cacheIndex,
50333
50334 lastActiveIndex = this._nActiveActions ++,
50335
50336 firstInactiveAction = actions[ lastActiveIndex ];
50337
50338 action._cacheIndex = lastActiveIndex;
50339 actions[ lastActiveIndex ] = action;
50340
50341 firstInactiveAction._cacheIndex = prevIndex;
50342 actions[ prevIndex ] = firstInactiveAction;
50343
50344 }
50345
50346 _takeBackAction( action ) {
50347
50348 // [ active actions | inactive actions ]
50349 // [ active actions |< inactive actions ]
50350 // a s
50351 // <-swap->
50352 // s a
50353
50354 const actions = this._actions,
50355 prevIndex = action._cacheIndex,
50356
50357 firstInactiveIndex = -- this._nActiveActions,
50358
50359 lastActiveAction = actions[ firstInactiveIndex ];
50360
50361 action._cacheIndex = firstInactiveIndex;
50362 actions[ firstInactiveIndex ] = action;
50363
50364 lastActiveAction._cacheIndex = prevIndex;
50365 actions[ prevIndex ] = lastActiveAction;
50366
50367 }
50368
50369 // Memory management for PropertyMixer objects
50370
50371 _addInactiveBinding( binding, rootUuid, trackName ) {
50372
50373 const bindingsByRoot = this._bindingsByRootAndName,
50374 bindings = this._bindings;
50375
50376 let bindingByName = bindingsByRoot[ rootUuid ];
50377
50378 if ( bindingByName === undefined ) {
50379
50380 bindingByName = {};
50381 bindingsByRoot[ rootUuid ] = bindingByName;
50382
50383 }
50384
50385 bindingByName[ trackName ] = binding;
50386
50387 binding._cacheIndex = bindings.length;
50388 bindings.push( binding );
50389
50390 }
50391
50392 _removeInactiveBinding( binding ) {
50393
50394 const bindings = this._bindings,
50395 propBinding = binding.binding,
50396 rootUuid = propBinding.rootNode.uuid,
50397 trackName = propBinding.path,
50398 bindingsByRoot = this._bindingsByRootAndName,
50399 bindingByName = bindingsByRoot[ rootUuid ],
50400
50401 lastInactiveBinding = bindings[ bindings.length - 1 ],
50402 cacheIndex = binding._cacheIndex;
50403
50404 lastInactiveBinding._cacheIndex = cacheIndex;
50405 bindings[ cacheIndex ] = lastInactiveBinding;
50406 bindings.pop();
50407
50408 delete bindingByName[ trackName ];
50409
50410 if ( Object.keys( bindingByName ).length === 0 ) {
50411
50412 delete bindingsByRoot[ rootUuid ];
50413
50414 }
50415
50416 }
50417
50418 _lendBinding( binding ) {
50419
50420 const bindings = this._bindings,
50421 prevIndex = binding._cacheIndex,
50422
50423 lastActiveIndex = this._nActiveBindings ++,
50424
50425 firstInactiveBinding = bindings[ lastActiveIndex ];
50426
50427 binding._cacheIndex = lastActiveIndex;
50428 bindings[ lastActiveIndex ] = binding;
50429
50430 firstInactiveBinding._cacheIndex = prevIndex;
50431 bindings[ prevIndex ] = firstInactiveBinding;
50432
50433 }
50434
50435 _takeBackBinding( binding ) {
50436
50437 const bindings = this._bindings,
50438 prevIndex = binding._cacheIndex,
50439
50440 firstInactiveIndex = -- this._nActiveBindings,
50441
50442 lastActiveBinding = bindings[ firstInactiveIndex ];
50443
50444 binding._cacheIndex = firstInactiveIndex;
50445 bindings[ firstInactiveIndex ] = binding;
50446
50447 lastActiveBinding._cacheIndex = prevIndex;
50448 bindings[ prevIndex ] = lastActiveBinding;
50449
50450 }
50451
50452
50453 // Memory management of Interpolants for weight and time scale
50454
50455 _lendControlInterpolant() {
50456
50457 const interpolants = this._controlInterpolants,
50458 lastActiveIndex = this._nActiveControlInterpolants ++;
50459
50460 let interpolant = interpolants[ lastActiveIndex ];
50461
50462 if ( interpolant === undefined ) {
50463
50464 interpolant = new LinearInterpolant(
50465 new Float32Array( 2 ), new Float32Array( 2 ),
50466 1, _controlInterpolantsResultBuffer );
50467
50468 interpolant.__cacheIndex = lastActiveIndex;
50469 interpolants[ lastActiveIndex ] = interpolant;
50470
50471 }
50472
50473 return interpolant;
50474
50475 }
50476
50477 _takeBackControlInterpolant( interpolant ) {
50478
50479 const interpolants = this._controlInterpolants,
50480 prevIndex = interpolant.__cacheIndex,
50481
50482 firstInactiveIndex = -- this._nActiveControlInterpolants,
50483
50484 lastActiveInterpolant = interpolants[ firstInactiveIndex ];
50485
50486 interpolant.__cacheIndex = firstInactiveIndex;
50487 interpolants[ firstInactiveIndex ] = interpolant;
50488
50489 lastActiveInterpolant.__cacheIndex = prevIndex;
50490 interpolants[ prevIndex ] = lastActiveInterpolant;
50491
50492 }
50493
50494 // return an action for a clip optionally using a custom root target
50495 // object (this method allocates a lot of dynamic memory in case a
50496 // previously unknown clip/root combination is specified)
50497 clipAction( clip, optionalRoot, blendMode ) {
50498
50499 const root = optionalRoot || this._root,
50500 rootUuid = root.uuid;
50501
50502 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;
50503
50504 const clipUuid = clipObject !== null ? clipObject.uuid : clip;
50505
50506 const actionsForClip = this._actionsByClip[ clipUuid ];
50507 let prototypeAction = null;
50508
50509 if ( blendMode === undefined ) {
50510
50511 if ( clipObject !== null ) {
50512
50513 blendMode = clipObject.blendMode;
50514
50515 } else {
50516
50517 blendMode = NormalAnimationBlendMode;
50518
50519 }
50520
50521 }
50522
50523 if ( actionsForClip !== undefined ) {
50524
50525 const existingAction = actionsForClip.actionByRoot[ rootUuid ];
50526
50527 if ( existingAction !== undefined && existingAction.blendMode === blendMode ) {
50528
50529 return existingAction;
50530
50531 }
50532
50533 // we know the clip, so we don't have to parse all
50534 // the bindings again but can just copy
50535 prototypeAction = actionsForClip.knownActions[ 0 ];
50536
50537 // also, take the clip from the prototype action
50538 if ( clipObject === null )
50539 clipObject = prototypeAction._clip;
50540
50541 }
50542
50543 // clip must be known when specified via string
50544 if ( clipObject === null ) return null;
50545
50546 // allocate all resources required to run it
50547 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );
50548
50549 this._bindAction( newAction, prototypeAction );
50550
50551 // and make the action known to the memory manager
50552 this._addInactiveAction( newAction, clipUuid, rootUuid );
50553
50554 return newAction;
50555
50556 }
50557
50558 // get an existing action
50559 existingAction( clip, optionalRoot ) {
50560
50561 const root = optionalRoot || this._root,
50562 rootUuid = root.uuid,
50563
50564 clipObject = typeof clip === 'string' ?
50565 AnimationClip.findByName( root, clip ) : clip,
50566
50567 clipUuid = clipObject ? clipObject.uuid : clip,
50568
50569 actionsForClip = this._actionsByClip[ clipUuid ];
50570
50571 if ( actionsForClip !== undefined ) {
50572
50573 return actionsForClip.actionByRoot[ rootUuid ] || null;
50574
50575 }
50576
50577 return null;
50578
50579 }
50580
50581 // deactivates all previously scheduled actions
50582 stopAllAction() {
50583
50584 const actions = this._actions,
50585 nActions = this._nActiveActions;
50586
50587 for ( let i = nActions - 1; i >= 0; -- i ) {
50588
50589 actions[ i ].stop();
50590
50591 }
50592
50593 return this;
50594
50595 }
50596
50597 // advance the time and update apply the animation
50598 update( deltaTime ) {
50599
50600 deltaTime *= this.timeScale;
50601
50602 const actions = this._actions,
50603 nActions = this._nActiveActions,
50604
50605 time = this.time += deltaTime,
50606 timeDirection = Math.sign( deltaTime ),
50607
50608 accuIndex = this._accuIndex ^= 1;
50609
50610 // run active actions
50611
50612 for ( let i = 0; i !== nActions; ++ i ) {
50613
50614 const action = actions[ i ];
50615
50616 action._update( time, deltaTime, timeDirection, accuIndex );
50617
50618 }
50619
50620 // update scene graph
50621
50622 const bindings = this._bindings,
50623 nBindings = this._nActiveBindings;
50624
50625 for ( let i = 0; i !== nBindings; ++ i ) {
50626
50627 bindings[ i ].apply( accuIndex );
50628
50629 }
50630
50631 return this;
50632
50633 }
50634
50635 // Allows you to seek to a specific time in an animation.
50636 setTime( timeInSeconds ) {
50637
50638 this.time = 0; // Zero out time attribute for AnimationMixer object;
50639 for ( let i = 0; i < this._actions.length; i ++ ) {
50640
50641 this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.
50642
50643 }
50644
50645 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object.
50646
50647 }
50648
50649 // return this mixer's root target object
50650 getRoot() {
50651
50652 return this._root;
50653
50654 }
50655
50656 // free all resources specific to a particular clip
50657 uncacheClip( clip ) {
50658
50659 const actions = this._actions,
50660 clipUuid = clip.uuid,
50661 actionsByClip = this._actionsByClip,
50662 actionsForClip = actionsByClip[ clipUuid ];
50663
50664 if ( actionsForClip !== undefined ) {
50665
50666 // note: just calling _removeInactiveAction would mess up the
50667 // iteration state and also require updating the state we can
50668 // just throw away
50669
50670 const actionsToRemove = actionsForClip.knownActions;
50671
50672 for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
50673
50674 const action = actionsToRemove[ i ];
50675
50676 this._deactivateAction( action );
50677
50678 const cacheIndex = action._cacheIndex,
50679 lastInactiveAction = actions[ actions.length - 1 ];
50680
50681 action._cacheIndex = null;
50682 action._byClipCacheIndex = null;
50683
50684 lastInactiveAction._cacheIndex = cacheIndex;
50685 actions[ cacheIndex ] = lastInactiveAction;
50686 actions.pop();
50687
50688 this._removeInactiveBindingsForAction( action );
50689
50690 }
50691
50692 delete actionsByClip[ clipUuid ];
50693
50694 }
50695
50696 }
50697
50698 // free all resources specific to a particular root target object
50699 uncacheRoot( root ) {
50700
50701 const rootUuid = root.uuid,
50702 actionsByClip = this._actionsByClip;
50703
50704 for ( const clipUuid in actionsByClip ) {
50705
50706 const actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
50707 action = actionByRoot[ rootUuid ];
50708
50709 if ( action !== undefined ) {
50710
50711 this._deactivateAction( action );
50712 this._removeInactiveAction( action );
50713
50714 }
50715
50716 }
50717
50718 const bindingsByRoot = this._bindingsByRootAndName,
50719 bindingByName = bindingsByRoot[ rootUuid ];
50720
50721 if ( bindingByName !== undefined ) {
50722
50723 for ( const trackName in bindingByName ) {
50724
50725 const binding = bindingByName[ trackName ];
50726 binding.restoreOriginalState();
50727 this._removeInactiveBinding( binding );
50728
50729 }
50730
50731 }
50732
50733 }
50734
50735 // remove a targeted clip from the cache
50736 uncacheAction( clip, optionalRoot ) {
50737
50738 const action = this.existingAction( clip, optionalRoot );
50739
50740 if ( action !== null ) {
50741
50742 this._deactivateAction( action );
50743 this._removeInactiveAction( action );
50744
50745 }
50746
50747 }
50748
50749 }
50750
50751 class Uniform {
50752
50753 constructor( value ) {
50754
50755 this.value = value;
50756
50757 }
50758
50759 clone() {
50760
50761 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
50762
50763 }
50764
50765 }
50766
50767 let _id = 0;
50768
50769 class UniformsGroup extends EventDispatcher {
50770
50771 constructor() {
50772
50773 super();
50774
50775 this.isUniformsGroup = true;
50776
50777 Object.defineProperty( this, 'id', { value: _id ++ } );
50778
50779 this.name = '';
50780
50781 this.usage = StaticDrawUsage;
50782 this.uniforms = [];
50783
50784 }
50785
50786 add( uniform ) {
50787
50788 this.uniforms.push( uniform );
50789
50790 return this;
50791
50792 }
50793
50794 remove( uniform ) {
50795
50796 const index = this.uniforms.indexOf( uniform );
50797
50798 if ( index !== - 1 ) this.uniforms.splice( index, 1 );
50799
50800 return this;
50801
50802 }
50803
50804 setName( name ) {
50805
50806 this.name = name;
50807
50808 return this;
50809
50810 }
50811
50812 setUsage( value ) {
50813
50814 this.usage = value;
50815
50816 return this;
50817
50818 }
50819
50820 dispose() {
50821
50822 this.dispatchEvent( { type: 'dispose' } );
50823
50824 return this;
50825
50826 }
50827
50828 copy( source ) {
50829
50830 this.name = source.name;
50831 this.usage = source.usage;
50832
50833 const uniformsSource = source.uniforms;
50834
50835 this.uniforms.length = 0;
50836
50837 for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) {
50838
50839 const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ];
50840
50841 for ( let j = 0; j < uniforms.length; j ++ ) {
50842
50843 this.uniforms.push( uniforms[ j ].clone() );
50844
50845 }
50846
50847 }
50848
50849 return this;
50850
50851 }
50852
50853 clone() {
50854
50855 return new this.constructor().copy( this );
50856
50857 }
50858
50859 }
50860
50861 class InstancedInterleavedBuffer extends InterleavedBuffer {
50862
50863 constructor( array, stride, meshPerAttribute = 1 ) {
50864
50865 super( array, stride );
50866
50867 this.isInstancedInterleavedBuffer = true;
50868
50869 this.meshPerAttribute = meshPerAttribute;
50870
50871 }
50872
50873 copy( source ) {
50874
50875 super.copy( source );
50876
50877 this.meshPerAttribute = source.meshPerAttribute;
50878
50879 return this;
50880
50881 }
50882
50883 clone( data ) {
50884
50885 const ib = super.clone( data );
50886
50887 ib.meshPerAttribute = this.meshPerAttribute;
50888
50889 return ib;
50890
50891 }
50892
50893 toJSON( data ) {
50894
50895 const json = super.toJSON( data );
50896
50897 json.isInstancedInterleavedBuffer = true;
50898 json.meshPerAttribute = this.meshPerAttribute;
50899
50900 return json;
50901
50902 }
50903
50904 }
50905
50906 class GLBufferAttribute {
50907
50908 constructor( buffer, type, itemSize, elementSize, count ) {
50909
50910 this.isGLBufferAttribute = true;
50911
50912 this.name = '';
50913
50914 this.buffer = buffer;
50915 this.type = type;
50916 this.itemSize = itemSize;
50917 this.elementSize = elementSize;
50918 this.count = count;
50919
50920 this.version = 0;
50921
50922 }
50923
50924 set needsUpdate( value ) {
50925
50926 if ( value === true ) this.version ++;
50927
50928 }
50929
50930 setBuffer( buffer ) {
50931
50932 this.buffer = buffer;
50933
50934 return this;
50935
50936 }
50937
50938 setType( type, elementSize ) {
50939
50940 this.type = type;
50941 this.elementSize = elementSize;
50942
50943 return this;
50944
50945 }
50946
50947 setItemSize( itemSize ) {
50948
50949 this.itemSize = itemSize;
50950
50951 return this;
50952
50953 }
50954
50955 setCount( count ) {
50956
50957 this.count = count;
50958
50959 return this;
50960
50961 }
50962
50963 }
50964
50965 class Raycaster {
50966
50967 constructor( origin, direction, near = 0, far = Infinity ) {
50968
50969 this.ray = new Ray( origin, direction );
50970 // direction is assumed to be normalized (for accurate distance calculations)
50971
50972 this.near = near;
50973 this.far = far;
50974 this.camera = null;
50975 this.layers = new Layers();
50976
50977 this.params = {
50978 Mesh: {},
50979 Line: { threshold: 1 },
50980 LOD: {},
50981 Points: { threshold: 1 },
50982 Sprite: {}
50983 };
50984
50985 }
50986
50987 set( origin, direction ) {
50988
50989 // direction is assumed to be normalized (for accurate distance calculations)
50990
50991 this.ray.set( origin, direction );
50992
50993 }
50994
50995 setFromCamera( coords, camera ) {
50996
50997 if ( camera.isPerspectiveCamera ) {
50998
50999 this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
51000 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
51001 this.camera = camera;
51002
51003 } else if ( camera.isOrthographicCamera ) {
51004
51005 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
51006 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
51007 this.camera = camera;
51008
51009 } else {
51010
51011 console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );
51012
51013 }
51014
51015 }
51016
51017 intersectObject( object, recursive = true, intersects = [] ) {
51018
51019 intersectObject( object, this, intersects, recursive );
51020
51021 intersects.sort( ascSort );
51022
51023 return intersects;
51024
51025 }
51026
51027 intersectObjects( objects, recursive = true, intersects = [] ) {
51028
51029 for ( let i = 0, l = objects.length; i < l; i ++ ) {
51030
51031 intersectObject( objects[ i ], this, intersects, recursive );
51032
51033 }
51034
51035 intersects.sort( ascSort );
51036
51037 return intersects;
51038
51039 }
51040
51041 }
51042
51043 function ascSort( a, b ) {
51044
51045 return a.distance - b.distance;
51046
51047 }
51048
51049 function intersectObject( object, raycaster, intersects, recursive ) {
51050
51051 if ( object.layers.test( raycaster.layers ) ) {
51052
51053 object.raycast( raycaster, intersects );
51054
51055 }
51056
51057 if ( recursive === true ) {
51058
51059 const children = object.children;
51060
51061 for ( let i = 0, l = children.length; i < l; i ++ ) {
51062
51063 intersectObject( children[ i ], raycaster, intersects, true );
51064
51065 }
51066
51067 }
51068
51069 }
51070
51079 class Spherical {
51080
51081 constructor( radius = 1, phi = 0, theta = 0 ) {
51082
51083 this.radius = radius;
51084 this.phi = phi; // polar angle
51085 this.theta = theta; // azimuthal angle
51086
51087 return this;
51088
51089 }
51090
51091 set( radius, phi, theta ) {
51092
51093 this.radius = radius;
51094 this.phi = phi;
51095 this.theta = theta;
51096
51097 return this;
51098
51099 }
51100
51101 copy( other ) {
51102
51103 this.radius = other.radius;
51104 this.phi = other.phi;
51105 this.theta = other.theta;
51106
51107 return this;
51108
51109 }
51110
51111 // restrict phi to be between EPS and PI-EPS
51112 makeSafe() {
51113
51114 const EPS = 0.000001;
51115 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );
51116
51117 return this;
51118
51119 }
51120
51121 setFromVector3( v ) {
51122
51123 return this.setFromCartesianCoords( v.x, v.y, v.z );
51124
51125 }
51126
51127 setFromCartesianCoords( x, y, z ) {
51128
51129 this.radius = Math.sqrt( x * x + y * y + z * z );
51130
51131 if ( this.radius === 0 ) {
51132
51133 this.theta = 0;
51134 this.phi = 0;
51135
51136 } else {
51137
51138 this.theta = Math.atan2( x, z );
51139 this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) );
51140
51141 }
51142
51143 return this;
51144
51145 }
51146
51147 clone() {
51148
51149 return new this.constructor().copy( this );
51150
51151 }
51152
51153 }
51154
51159 class Cylindrical {
51160
51161 constructor( radius = 1, theta = 0, y = 0 ) {
51162
51163 this.radius = radius; // distance from the origin to a point in the x-z plane
51164 this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
51165 this.y = y; // height above the x-z plane
51166
51167 return this;
51168
51169 }
51170
51171 set( radius, theta, y ) {
51172
51173 this.radius = radius;
51174 this.theta = theta;
51175 this.y = y;
51176
51177 return this;
51178
51179 }
51180
51181 copy( other ) {
51182
51183 this.radius = other.radius;
51184 this.theta = other.theta;
51185 this.y = other.y;
51186
51187 return this;
51188
51189 }
51190
51191 setFromVector3( v ) {
51192
51193 return this.setFromCartesianCoords( v.x, v.y, v.z );
51194
51195 }
51196
51197 setFromCartesianCoords( x, y, z ) {
51198
51199 this.radius = Math.sqrt( x * x + z * z );
51200 this.theta = Math.atan2( x, z );
51201 this.y = y;
51202
51203 return this;
51204
51205 }
51206
51207 clone() {
51208
51209 return new this.constructor().copy( this );
51210
51211 }
51212
51213 }
51214
51215 const _vector$4 = /*@__PURE__*/ new Vector2();
51216
51217 class Box2 {
51218
51219 constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) {
51220
51221 this.isBox2 = true;
51222
51223 this.min = min;
51224 this.max = max;
51225
51226 }
51227
51228 set( min, max ) {
51229
51230 this.min.copy( min );
51231 this.max.copy( max );
51232
51233 return this;
51234
51235 }
51236
51237 setFromPoints( points ) {
51238
51239 this.makeEmpty();
51240
51241 for ( let i = 0, il = points.length; i < il; i ++ ) {
51242
51243 this.expandByPoint( points[ i ] );
51244
51245 }
51246
51247 return this;
51248
51249 }
51250
51251 setFromCenterAndSize( center, size ) {
51252
51253 const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 );
51254 this.min.copy( center ).sub( halfSize );
51255 this.max.copy( center ).add( halfSize );
51256
51257 return this;
51258
51259 }
51260
51261 clone() {
51262
51263 return new this.constructor().copy( this );
51264
51265 }
51266
51267 copy( box ) {
51268
51269 this.min.copy( box.min );
51270 this.max.copy( box.max );
51271
51272 return this;
51273
51274 }
51275
51276 makeEmpty() {
51277
51278 this.min.x = this.min.y = + Infinity;
51279 this.max.x = this.max.y = - Infinity;
51280
51281 return this;
51282
51283 }
51284
51285 isEmpty() {
51286
51287 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
51288
51289 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
51290
51291 }
51292
51293 getCenter( target ) {
51294
51295 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
51296
51297 }
51298
51299 getSize( target ) {
51300
51301 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );
51302
51303 }
51304
51305 expandByPoint( point ) {
51306
51307 this.min.min( point );
51308 this.max.max( point );
51309
51310 return this;
51311
51312 }
51313
51314 expandByVector( vector ) {
51315
51316 this.min.sub( vector );
51317 this.max.add( vector );
51318
51319 return this;
51320
51321 }
51322
51323 expandByScalar( scalar ) {
51324
51325 this.min.addScalar( - scalar );
51326 this.max.addScalar( scalar );
51327
51328 return this;
51329
51330 }
51331
51332 containsPoint( point ) {
51333
51334 return point.x < this.min.x || point.x > this.max.x ||
51335 point.y < this.min.y || point.y > this.max.y ? false : true;
51336
51337 }
51338
51339 containsBox( box ) {
51340
51341 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
51342 this.min.y <= box.min.y && box.max.y <= this.max.y;
51343
51344 }
51345
51346 getParameter( point, target ) {
51347
51348 // This can potentially have a divide by zero if the box
51349 // has a size dimension of 0.
51350
51351 return target.set(
51352 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
51353 ( point.y - this.min.y ) / ( this.max.y - this.min.y )
51354 );
51355
51356 }
51357
51358 intersectsBox( box ) {
51359
51360 // using 4 splitting planes to rule out intersections
51361
51362 return box.max.x < this.min.x || box.min.x > this.max.x ||
51363 box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
51364
51365 }
51366
51367 clampPoint( point, target ) {
51368
51369 return target.copy( point ).clamp( this.min, this.max );
51370
51371 }
51372
51373 distanceToPoint( point ) {
51374
51375 return this.clampPoint( point, _vector$4 ).distanceTo( point );
51376
51377 }
51378
51379 intersect( box ) {
51380
51381 this.min.max( box.min );
51382 this.max.min( box.max );
51383
51384 if ( this.isEmpty() ) this.makeEmpty();
51385
51386 return this;
51387
51388 }
51389
51390 union( box ) {
51391
51392 this.min.min( box.min );
51393 this.max.max( box.max );
51394
51395 return this;
51396
51397 }
51398
51399 translate( offset ) {
51400
51401 this.min.add( offset );
51402 this.max.add( offset );
51403
51404 return this;
51405
51406 }
51407
51408 equals( box ) {
51409
51410 return box.min.equals( this.min ) && box.max.equals( this.max );
51411
51412 }
51413
51414 }
51415
51416 const _startP = /*@__PURE__*/ new Vector3();
51417 const _startEnd = /*@__PURE__*/ new Vector3();
51418
51419 class Line3 {
51420
51421 constructor( start = new Vector3(), end = new Vector3() ) {
51422
51423 this.start = start;
51424 this.end = end;
51425
51426 }
51427
51428 set( start, end ) {
51429
51430 this.start.copy( start );
51431 this.end.copy( end );
51432
51433 return this;
51434
51435 }
51436
51437 copy( line ) {
51438
51439 this.start.copy( line.start );
51440 this.end.copy( line.end );
51441
51442 return this;
51443
51444 }
51445
51446 getCenter( target ) {
51447
51448 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
51449
51450 }
51451
51452 delta( target ) {
51453
51454 return target.subVectors( this.end, this.start );
51455
51456 }
51457
51458 distanceSq() {
51459
51460 return this.start.distanceToSquared( this.end );
51461
51462 }
51463
51464 distance() {
51465
51466 return this.start.distanceTo( this.end );
51467
51468 }
51469
51470 at( t, target ) {
51471
51472 return this.delta( target ).multiplyScalar( t ).add( this.start );
51473
51474 }
51475
51476 closestPointToPointParameter( point, clampToLine ) {
51477
51478 _startP.subVectors( point, this.start );
51479 _startEnd.subVectors( this.end, this.start );
51480
51481 const startEnd2 = _startEnd.dot( _startEnd );
51482 const startEnd_startP = _startEnd.dot( _startP );
51483
51484 let t = startEnd_startP / startEnd2;
51485
51486 if ( clampToLine ) {
51487
51488 t = clamp( t, 0, 1 );
51489
51490 }
51491
51492 return t;
51493
51494 }
51495
51496 closestPointToPoint( point, clampToLine, target ) {
51497
51498 const t = this.closestPointToPointParameter( point, clampToLine );
51499
51500 return this.delta( target ).multiplyScalar( t ).add( this.start );
51501
51502 }
51503
51504 applyMatrix4( matrix ) {
51505
51506 this.start.applyMatrix4( matrix );
51507 this.end.applyMatrix4( matrix );
51508
51509 return this;
51510
51511 }
51512
51513 equals( line ) {
51514
51515 return line.start.equals( this.start ) && line.end.equals( this.end );
51516
51517 }
51518
51519 clone() {
51520
51521 return new this.constructor().copy( this );
51522
51523 }
51524
51525 }
51526
51527 const _vector$3 = /*@__PURE__*/ new Vector3();
51528
51529 class SpotLightHelper extends Object3D {
51530
51531 constructor( light, color ) {
51532
51533 super();
51534
51535 this.light = light;
51536
51537 this.matrix = light.matrixWorld;
51538 this.matrixAutoUpdate = false;
51539
51540 this.color = color;
51541
51542 this.type = 'SpotLightHelper';
51543
51544 const geometry = new BufferGeometry();
51545
51546 const positions = [
51547 0, 0, 0, 0, 0, 1,
51548 0, 0, 0, 1, 0, 1,
51549 0, 0, 0, - 1, 0, 1,
51550 0, 0, 0, 0, 1, 1,
51551 0, 0, 0, 0, - 1, 1
51552 ];
51553
51554 for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
51555
51556 const p1 = ( i / l ) * Math.PI * 2;
51557 const p2 = ( j / l ) * Math.PI * 2;
51558
51559 positions.push(
51560 Math.cos( p1 ), Math.sin( p1 ), 1,
51561 Math.cos( p2 ), Math.sin( p2 ), 1
51562 );
51563
51564 }
51565
51566 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
51567
51568 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
51569
51570 this.cone = new LineSegments( geometry, material );
51571 this.add( this.cone );
51572
51573 this.update();
51574
51575 }
51576
51577 dispose() {
51578
51579 this.cone.geometry.dispose();
51580 this.cone.material.dispose();
51581
51582 }
51583
51584 update() {
51585
51586 this.light.updateWorldMatrix( true, false );
51587 this.light.target.updateWorldMatrix( true, false );
51588
51589 const coneLength = this.light.distance ? this.light.distance : 1000;
51590 const coneWidth = coneLength * Math.tan( this.light.angle );
51591
51592 this.cone.scale.set( coneWidth, coneWidth, coneLength );
51593
51594 _vector$3.setFromMatrixPosition( this.light.target.matrixWorld );
51595
51596 this.cone.lookAt( _vector$3 );
51597
51598 if ( this.color !== undefined ) {
51599
51600 this.cone.material.color.set( this.color );
51601
51602 } else {
51603
51604 this.cone.material.color.copy( this.light.color );
51605
51606 }
51607
51608 }
51609
51610 }
51611
51612 const _vector$2 = /*@__PURE__*/ new Vector3();
51613 const _boneMatrix = /*@__PURE__*/ new Matrix4();
51614 const _matrixWorldInv = /*@__PURE__*/ new Matrix4();
51615
51616
51617 class SkeletonHelper extends LineSegments {
51618
51619 constructor( object ) {
51620
51621 const bones = getBoneList( object );
51622
51623 const geometry = new BufferGeometry();
51624
51625 const vertices = [];
51626 const colors = [];
51627
51628 const color1 = new Color( 0, 0, 1 );
51629 const color2 = new Color( 0, 1, 0 );
51630
51631 for ( let i = 0; i < bones.length; i ++ ) {
51632
51633 const bone = bones[ i ];
51634
51635 if ( bone.parent && bone.parent.isBone ) {
51636
51637 vertices.push( 0, 0, 0 );
51638 vertices.push( 0, 0, 0 );
51639 colors.push( color1.r, color1.g, color1.b );
51640 colors.push( color2.r, color2.g, color2.b );
51641
51642 }
51643
51644 }
51645
51646 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51647 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51648
51649 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
51650
51651 super( geometry, material );
51652
51653 this.isSkeletonHelper = true;
51654
51655 this.type = 'SkeletonHelper';
51656
51657 this.root = object;
51658 this.bones = bones;
51659
51660 this.matrix = object.matrixWorld;
51661 this.matrixAutoUpdate = false;
51662
51663 }
51664
51665 updateMatrixWorld( force ) {
51666
51667 const bones = this.bones;
51668
51669 const geometry = this.geometry;
51670 const position = geometry.getAttribute( 'position' );
51671
51672 _matrixWorldInv.copy( this.root.matrixWorld ).invert();
51673
51674 for ( let i = 0, j = 0; i < bones.length; i ++ ) {
51675
51676 const bone = bones[ i ];
51677
51678 if ( bone.parent && bone.parent.isBone ) {
51679
51680 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
51681 _vector$2.setFromMatrixPosition( _boneMatrix );
51682 position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );
51683
51684 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
51685 _vector$2.setFromMatrixPosition( _boneMatrix );
51686 position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );
51687
51688 j += 2;
51689
51690 }
51691
51692 }
51693
51694 geometry.getAttribute( 'position' ).needsUpdate = true;
51695
51696 super.updateMatrixWorld( force );
51697
51698 }
51699
51700 dispose() {
51701
51702 this.geometry.dispose();
51703 this.material.dispose();
51704
51705 }
51706
51707 }
51708
51709
51710 function getBoneList( object ) {
51711
51712 const boneList = [];
51713
51714 if ( object.isBone === true ) {
51715
51716 boneList.push( object );
51717
51718 }
51719
51720 for ( let i = 0; i < object.children.length; i ++ ) {
51721
51722 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
51723
51724 }
51725
51726 return boneList;
51727
51728 }
51729
51730 class PointLightHelper extends Mesh {
51731
51732 constructor( light, sphereSize, color ) {
51733
51734 const geometry = new SphereGeometry( sphereSize, 4, 2 );
51735 const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51736
51737 super( geometry, material );
51738
51739 this.light = light;
51740
51741 this.color = color;
51742
51743 this.type = 'PointLightHelper';
51744
51745 this.matrix = this.light.matrixWorld;
51746 this.matrixAutoUpdate = false;
51747
51748 this.update();
51749
51750
51751 /*
51752 // TODO: delete this comment?
51753 const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
51754 const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
51755
51756 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );
51757 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );
51758
51759 const d = light.distance;
51760
51761 if ( d === 0.0 ) {
51762
51763 this.lightDistance.visible = false;
51764
51765 } else {
51766
51767 this.lightDistance.scale.set( d, d, d );
51768
51769 }
51770
51771 this.add( this.lightDistance );
51772 */
51773
51774 }
51775
51776 dispose() {
51777
51778 this.geometry.dispose();
51779 this.material.dispose();
51780
51781 }
51782
51783 update() {
51784
51785 this.light.updateWorldMatrix( true, false );
51786
51787 if ( this.color !== undefined ) {
51788
51789 this.material.color.set( this.color );
51790
51791 } else {
51792
51793 this.material.color.copy( this.light.color );
51794
51795 }
51796
51797 /*
51798 const d = this.light.distance;
51799
51800 if ( d === 0.0 ) {
51801
51802 this.lightDistance.visible = false;
51803
51804 } else {
51805
51806 this.lightDistance.visible = true;
51807 this.lightDistance.scale.set( d, d, d );
51808
51809 }
51810 */
51811
51812 }
51813
51814 }
51815
51816 const _vector$1 = /*@__PURE__*/ new Vector3();
51817 const _color1 = /*@__PURE__*/ new Color();
51818 const _color2 = /*@__PURE__*/ new Color();
51819
51820 class HemisphereLightHelper extends Object3D {
51821
51822 constructor( light, size, color ) {
51823
51824 super();
51825
51826 this.light = light;
51827
51828 this.matrix = light.matrixWorld;
51829 this.matrixAutoUpdate = false;
51830
51831 this.color = color;
51832
51833 this.type = 'HemisphereLightHelper';
51834
51835 const geometry = new OctahedronGeometry( size );
51836 geometry.rotateY( Math.PI * 0.5 );
51837
51838 this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
51839 if ( this.color === undefined ) this.material.vertexColors = true;
51840
51841 const position = geometry.getAttribute( 'position' );
51842 const colors = new Float32Array( position.count * 3 );
51843
51844 geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
51845
51846 this.add( new Mesh( geometry, this.material ) );
51847
51848 this.update();
51849
51850 }
51851
51852 dispose() {
51853
51854 this.children[ 0 ].geometry.dispose();
51855 this.children[ 0 ].material.dispose();
51856
51857 }
51858
51859 update() {
51860
51861 const mesh = this.children[ 0 ];
51862
51863 if ( this.color !== undefined ) {
51864
51865 this.material.color.set( this.color );
51866
51867 } else {
51868
51869 const colors = mesh.geometry.getAttribute( 'color' );
51870
51871 _color1.copy( this.light.color );
51872 _color2.copy( this.light.groundColor );
51873
51874 for ( let i = 0, l = colors.count; i < l; i ++ ) {
51875
51876 const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
51877
51878 colors.setXYZ( i, color.r, color.g, color.b );
51879
51880 }
51881
51882 colors.needsUpdate = true;
51883
51884 }
51885
51886 this.light.updateWorldMatrix( true, false );
51887
51888 mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() );
51889
51890 }
51891
51892 }
51893
51894 class GridHelper extends LineSegments {
51895
51896 constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {
51897
51898 color1 = new Color( color1 );
51899 color2 = new Color( color2 );
51900
51901 const center = divisions / 2;
51902 const step = size / divisions;
51903 const halfSize = size / 2;
51904
51905 const vertices = [], colors = [];
51906
51907 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
51908
51909 vertices.push( - halfSize, 0, k, halfSize, 0, k );
51910 vertices.push( k, 0, - halfSize, k, 0, halfSize );
51911
51912 const color = i === center ? color1 : color2;
51913
51914 color.toArray( colors, j ); j += 3;
51915 color.toArray( colors, j ); j += 3;
51916 color.toArray( colors, j ); j += 3;
51917 color.toArray( colors, j ); j += 3;
51918
51919 }
51920
51921 const geometry = new BufferGeometry();
51922 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
51923 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
51924
51925 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
51926
51927 super( geometry, material );
51928
51929 this.type = 'GridHelper';
51930
51931 }
51932
51933 dispose() {
51934
51935 this.geometry.dispose();
51936 this.material.dispose();
51937
51938 }
51939
51940 }
51941
51942 class PolarGridHelper extends LineSegments {
51943
51944 constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {
51945
51946 color1 = new Color( color1 );
51947 color2 = new Color( color2 );
51948
51949 const vertices = [];
51950 const colors = [];
51951
51952 // create the sectors
51953
51954 if ( sectors > 1 ) {
51955
51956 for ( let i = 0; i < sectors; i ++ ) {
51957
51958 const v = ( i / sectors ) * ( Math.PI * 2 );
51959
51960 const x = Math.sin( v ) * radius;
51961 const z = Math.cos( v ) * radius;
51962
51963 vertices.push( 0, 0, 0 );
51964 vertices.push( x, 0, z );
51965
51966 const color = ( i & 1 ) ? color1 : color2;
51967
51968 colors.push( color.r, color.g, color.b );
51969 colors.push( color.r, color.g, color.b );
51970
51971 }
51972
51973 }
51974
51975 // create the rings
51976
51977 for ( let i = 0; i < rings; i ++ ) {
51978
51979 const color = ( i & 1 ) ? color1 : color2;
51980
51981 const r = radius - ( radius / rings * i );
51982
51983 for ( let j = 0; j < divisions; j ++ ) {
51984
51985 // first vertex
51986
51987 let v = ( j / divisions ) * ( Math.PI * 2 );
51988
51989 let x = Math.sin( v ) * r;
51990 let z = Math.cos( v ) * r;
51991
51992 vertices.push( x, 0, z );
51993 colors.push( color.r, color.g, color.b );
51994
51995 // second vertex
51996
51997 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
51998
51999 x = Math.sin( v ) * r;
52000 z = Math.cos( v ) * r;
52001
52002 vertices.push( x, 0, z );
52003 colors.push( color.r, color.g, color.b );
52004
52005 }
52006
52007 }
52008
52009 const geometry = new BufferGeometry();
52010 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52011 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52012
52013 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52014
52015 super( geometry, material );
52016
52017 this.type = 'PolarGridHelper';
52018
52019 }
52020
52021 dispose() {
52022
52023 this.geometry.dispose();
52024 this.material.dispose();
52025
52026 }
52027
52028 }
52029
52030 const _v1 = /*@__PURE__*/ new Vector3();
52031 const _v2 = /*@__PURE__*/ new Vector3();
52032 const _v3 = /*@__PURE__*/ new Vector3();
52033
52034 class DirectionalLightHelper extends Object3D {
52035
52036 constructor( light, size, color ) {
52037
52038 super();
52039
52040 this.light = light;
52041
52042 this.matrix = light.matrixWorld;
52043 this.matrixAutoUpdate = false;
52044
52045 this.color = color;
52046
52047 this.type = 'DirectionalLightHelper';
52048
52049 if ( size === undefined ) size = 1;
52050
52051 let geometry = new BufferGeometry();
52052 geometry.setAttribute( 'position', new Float32BufferAttribute( [
52053 - size, size, 0,
52054 size, size, 0,
52055 size, - size, 0,
52056 - size, - size, 0,
52057 - size, size, 0
52058 ], 3 ) );
52059
52060 const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
52061
52062 this.lightPlane = new Line( geometry, material );
52063 this.add( this.lightPlane );
52064
52065 geometry = new BufferGeometry();
52066 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
52067
52068 this.targetLine = new Line( geometry, material );
52069 this.add( this.targetLine );
52070
52071 this.update();
52072
52073 }
52074
52075 dispose() {
52076
52077 this.lightPlane.geometry.dispose();
52078 this.lightPlane.material.dispose();
52079 this.targetLine.geometry.dispose();
52080 this.targetLine.material.dispose();
52081
52082 }
52083
52084 update() {
52085
52086 this.light.updateWorldMatrix( true, false );
52087 this.light.target.updateWorldMatrix( true, false );
52088
52089 _v1.setFromMatrixPosition( this.light.matrixWorld );
52090 _v2.setFromMatrixPosition( this.light.target.matrixWorld );
52091 _v3.subVectors( _v2, _v1 );
52092
52093 this.lightPlane.lookAt( _v2 );
52094
52095 if ( this.color !== undefined ) {
52096
52097 this.lightPlane.material.color.set( this.color );
52098 this.targetLine.material.color.set( this.color );
52099
52100 } else {
52101
52102 this.lightPlane.material.color.copy( this.light.color );
52103 this.targetLine.material.color.copy( this.light.color );
52104
52105 }
52106
52107 this.targetLine.lookAt( _v2 );
52108 this.targetLine.scale.z = _v3.length();
52109
52110 }
52111
52112 }
52113
52114 const _vector = /*@__PURE__*/ new Vector3();
52115 const _camera = /*@__PURE__*/ new Camera();
52116
52124 class CameraHelper extends LineSegments {
52125
52126 constructor( camera ) {
52127
52128 const geometry = new BufferGeometry();
52129 const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
52130
52131 const vertices = [];
52132 const colors = [];
52133
52134 const pointMap = {};
52135
52136 // near
52137
52138 addLine( 'n1', 'n2' );
52139 addLine( 'n2', 'n4' );
52140 addLine( 'n4', 'n3' );
52141 addLine( 'n3', 'n1' );
52142
52143 // far
52144
52145 addLine( 'f1', 'f2' );
52146 addLine( 'f2', 'f4' );
52147 addLine( 'f4', 'f3' );
52148 addLine( 'f3', 'f1' );
52149
52150 // sides
52151
52152 addLine( 'n1', 'f1' );
52153 addLine( 'n2', 'f2' );
52154 addLine( 'n3', 'f3' );
52155 addLine( 'n4', 'f4' );
52156
52157 // cone
52158
52159 addLine( 'p', 'n1' );
52160 addLine( 'p', 'n2' );
52161 addLine( 'p', 'n3' );
52162 addLine( 'p', 'n4' );
52163
52164 // up
52165
52166 addLine( 'u1', 'u2' );
52167 addLine( 'u2', 'u3' );
52168 addLine( 'u3', 'u1' );
52169
52170 // target
52171
52172 addLine( 'c', 't' );
52173 addLine( 'p', 'c' );
52174
52175 // cross
52176
52177 addLine( 'cn1', 'cn2' );
52178 addLine( 'cn3', 'cn4' );
52179
52180 addLine( 'cf1', 'cf2' );
52181 addLine( 'cf3', 'cf4' );
52182
52183 function addLine( a, b ) {
52184
52185 addPoint( a );
52186 addPoint( b );
52187
52188 }
52189
52190 function addPoint( id ) {
52191
52192 vertices.push( 0, 0, 0 );
52193 colors.push( 0, 0, 0 );
52194
52195 if ( pointMap[ id ] === undefined ) {
52196
52197 pointMap[ id ] = [];
52198
52199 }
52200
52201 pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
52202
52203 }
52204
52205 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52206 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52207
52208 super( geometry, material );
52209
52210 this.type = 'CameraHelper';
52211
52212 this.camera = camera;
52213 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
52214
52215 this.matrix = camera.matrixWorld;
52216 this.matrixAutoUpdate = false;
52217
52218 this.pointMap = pointMap;
52219
52220 this.update();
52221
52222 // colors
52223
52224 const colorFrustum = new Color( 0xffaa00 );
52225 const colorCone = new Color( 0xff0000 );
52226 const colorUp = new Color( 0x00aaff );
52227 const colorTarget = new Color( 0xffffff );
52228 const colorCross = new Color( 0x333333 );
52229
52230 this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross );
52231
52232 }
52233
52234 setColors( frustum, cone, up, target, cross ) {
52235
52236 const geometry = this.geometry;
52237
52238 const colorAttribute = geometry.getAttribute( 'color' );
52239
52240 // near
52241
52242 colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2
52243 colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4
52244 colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3
52245 colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1
52246
52247 // far
52248
52249 colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2
52250 colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4
52251 colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3
52252 colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1
52253
52254 // sides
52255
52256 colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1
52257 colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2
52258 colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3
52259 colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4
52260
52261 // cone
52262
52263 colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1
52264 colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2
52265 colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3
52266 colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4
52267
52268 // up
52269
52270 colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2
52271 colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3
52272 colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1
52273
52274 // target
52275
52276 colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t
52277 colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c
52278
52279 // cross
52280
52281 colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2
52282 colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4
52283
52284 colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2
52285 colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4
52286
52287 colorAttribute.needsUpdate = true;
52288
52289 }
52290
52291 update() {
52292
52293 const geometry = this.geometry;
52294 const pointMap = this.pointMap;
52295
52296 const w = 1, h = 1;
52297
52298 // we need just camera projection matrix inverse
52299 // world matrix must be identity
52300
52301 _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
52302
52303 // center / target
52304
52305 setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
52306 setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
52307
52308 // near
52309
52310 setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
52311 setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
52312 setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
52313 setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
52314
52315 // far
52316
52317 setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
52318 setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
52319 setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
52320 setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
52321
52322 // up
52323
52324 setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
52325 setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
52326 setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
52327
52328 // cross
52329
52330 setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
52331 setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
52332 setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
52333 setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
52334
52335 setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
52336 setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
52337 setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
52338 setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
52339
52340 geometry.getAttribute( 'position' ).needsUpdate = true;
52341
52342 }
52343
52344 dispose() {
52345
52346 this.geometry.dispose();
52347 this.material.dispose();
52348
52349 }
52350
52351 }
52352
52353
52354 function setPoint( point, pointMap, geometry, camera, x, y, z ) {
52355
52356 _vector.set( x, y, z ).unproject( camera );
52357
52358 const points = pointMap[ point ];
52359
52360 if ( points !== undefined ) {
52361
52362 const position = geometry.getAttribute( 'position' );
52363
52364 for ( let i = 0, l = points.length; i < l; i ++ ) {
52365
52366 position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z );
52367
52368 }
52369
52370 }
52371
52372 }
52373
52374 const _box = /*@__PURE__*/ new Box3();
52375
52376 class BoxHelper extends LineSegments {
52377
52378 constructor( object, color = 0xffff00 ) {
52379
52380 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
52381 const positions = new Float32Array( 8 * 3 );
52382
52383 const geometry = new BufferGeometry();
52384 geometry.setIndex( new BufferAttribute( indices, 1 ) );
52385 geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
52386
52387 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52388
52389 this.object = object;
52390 this.type = 'BoxHelper';
52391
52392 this.matrixAutoUpdate = false;
52393
52394 this.update();
52395
52396 }
52397
52398 update( object ) {
52399
52400 if ( object !== undefined ) {
52401
52402 console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
52403
52404 }
52405
52406 if ( this.object !== undefined ) {
52407
52408 _box.setFromObject( this.object );
52409
52410 }
52411
52412 if ( _box.isEmpty() ) return;
52413
52414 const min = _box.min;
52415 const max = _box.max;
52416
52417 /*
52418 5____4
52419 1/___0/|
52420 | 6__|_7
52421 2/___3/
52422
52423 0: max.x, max.y, max.z
52424 1: min.x, max.y, max.z
52425 2: min.x, min.y, max.z
52426 3: max.x, min.y, max.z
52427 4: max.x, max.y, min.z
52428 5: min.x, max.y, min.z
52429 6: min.x, min.y, min.z
52430 7: max.x, min.y, min.z
52431 */
52432
52433 const position = this.geometry.attributes.position;
52434 const array = position.array;
52435
52436 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
52437 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
52438 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
52439 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
52440 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
52441 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
52442 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
52443 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
52444
52445 position.needsUpdate = true;
52446
52447 this.geometry.computeBoundingSphere();
52448
52449 }
52450
52451 setFromObject( object ) {
52452
52453 this.object = object;
52454 this.update();
52455
52456 return this;
52457
52458 }
52459
52460 copy( source, recursive ) {
52461
52462 super.copy( source, recursive );
52463
52464 this.object = source.object;
52465
52466 return this;
52467
52468 }
52469
52470 dispose() {
52471
52472 this.geometry.dispose();
52473 this.material.dispose();
52474
52475 }
52476
52477 }
52478
52479 class Box3Helper extends LineSegments {
52480
52481 constructor( box, color = 0xffff00 ) {
52482
52483 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
52484
52485 const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
52486
52487 const geometry = new BufferGeometry();
52488
52489 geometry.setIndex( new BufferAttribute( indices, 1 ) );
52490
52491 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52492
52493 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52494
52495 this.box = box;
52496
52497 this.type = 'Box3Helper';
52498
52499 this.geometry.computeBoundingSphere();
52500
52501 }
52502
52503 updateMatrixWorld( force ) {
52504
52505 const box = this.box;
52506
52507 if ( box.isEmpty() ) return;
52508
52509 box.getCenter( this.position );
52510
52511 box.getSize( this.scale );
52512
52513 this.scale.multiplyScalar( 0.5 );
52514
52515 super.updateMatrixWorld( force );
52516
52517 }
52518
52519 dispose() {
52520
52521 this.geometry.dispose();
52522 this.material.dispose();
52523
52524 }
52525
52526 }
52527
52528 class PlaneHelper extends Line {
52529
52530 constructor( plane, size = 1, hex = 0xffff00 ) {
52531
52532 const color = hex;
52533
52534 const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ];
52535
52536 const geometry = new BufferGeometry();
52537 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
52538 geometry.computeBoundingSphere();
52539
52540 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52541
52542 this.type = 'PlaneHelper';
52543
52544 this.plane = plane;
52545
52546 this.size = size;
52547
52548 const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];
52549
52550 const geometry2 = new BufferGeometry();
52551 geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
52552 geometry2.computeBoundingSphere();
52553
52554 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
52555
52556 }
52557
52558 updateMatrixWorld( force ) {
52559
52560 this.position.set( 0, 0, 0 );
52561
52562 this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 );
52563
52564 this.lookAt( this.plane.normal );
52565
52566 this.translateZ( - this.plane.constant );
52567
52568 super.updateMatrixWorld( force );
52569
52570 }
52571
52572 dispose() {
52573
52574 this.geometry.dispose();
52575 this.material.dispose();
52576 this.children[ 0 ].geometry.dispose();
52577 this.children[ 0 ].material.dispose();
52578
52579 }
52580
52581 }
52582
52583 const _axis = /*@__PURE__*/ new Vector3();
52584 let _lineGeometry, _coneGeometry;
52585
52586 class ArrowHelper extends Object3D {
52587
52588 // dir is assumed to be normalized
52589
52590 constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) {
52591
52592 super();
52593
52594 this.type = 'ArrowHelper';
52595
52596 if ( _lineGeometry === undefined ) {
52597
52598 _lineGeometry = new BufferGeometry();
52599 _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
52600
52601 _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );
52602 _coneGeometry.translate( 0, - 0.5, 0 );
52603
52604 }
52605
52606 this.position.copy( origin );
52607
52608 this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
52609 this.line.matrixAutoUpdate = false;
52610 this.add( this.line );
52611
52612 this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
52613 this.cone.matrixAutoUpdate = false;
52614 this.add( this.cone );
52615
52616 this.setDirection( dir );
52617 this.setLength( length, headLength, headWidth );
52618
52619 }
52620
52621 setDirection( dir ) {
52622
52623 // dir is assumed to be normalized
52624
52625 if ( dir.y > 0.99999 ) {
52626
52627 this.quaternion.set( 0, 0, 0, 1 );
52628
52629 } else if ( dir.y < - 0.99999 ) {
52630
52631 this.quaternion.set( 1, 0, 0, 0 );
52632
52633 } else {
52634
52635 _axis.set( dir.z, 0, - dir.x ).normalize();
52636
52637 const radians = Math.acos( dir.y );
52638
52639 this.quaternion.setFromAxisAngle( _axis, radians );
52640
52641 }
52642
52643 }
52644
52645 setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) {
52646
52647 this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
52648 this.line.updateMatrix();
52649
52650 this.cone.scale.set( headWidth, headLength, headWidth );
52651 this.cone.position.y = length;
52652 this.cone.updateMatrix();
52653
52654 }
52655
52656 setColor( color ) {
52657
52658 this.line.material.color.set( color );
52659 this.cone.material.color.set( color );
52660
52661 }
52662
52663 copy( source ) {
52664
52665 super.copy( source, false );
52666
52667 this.line.copy( source.line );
52668 this.cone.copy( source.cone );
52669
52670 return this;
52671
52672 }
52673
52674 dispose() {
52675
52676 this.line.geometry.dispose();
52677 this.line.material.dispose();
52678 this.cone.geometry.dispose();
52679 this.cone.material.dispose();
52680
52681 }
52682
52683 }
52684
52685 class AxesHelper extends LineSegments {
52686
52687 constructor( size = 1 ) {
52688
52689 const vertices = [
52690 0, 0, 0, size, 0, 0,
52691 0, 0, 0, 0, size, 0,
52692 0, 0, 0, 0, 0, size
52693 ];
52694
52695 const colors = [
52696 1, 0, 0, 1, 0.6, 0,
52697 0, 1, 0, 0.6, 1, 0,
52698 0, 0, 1, 0, 0.6, 1
52699 ];
52700
52701 const geometry = new BufferGeometry();
52702 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
52703 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
52704
52705 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
52706
52707 super( geometry, material );
52708
52709 this.type = 'AxesHelper';
52710
52711 }
52712
52713 setColors( xAxisColor, yAxisColor, zAxisColor ) {
52714
52715 const color = new Color();
52716 const array = this.geometry.attributes.color.array;
52717
52718 color.set( xAxisColor );
52719 color.toArray( array, 0 );
52720 color.toArray( array, 3 );
52721
52722 color.set( yAxisColor );
52723 color.toArray( array, 6 );
52724 color.toArray( array, 9 );
52725
52726 color.set( zAxisColor );
52727 color.toArray( array, 12 );
52728 color.toArray( array, 15 );
52729
52730 this.geometry.attributes.color.needsUpdate = true;
52731
52732 return this;
52733
52734 }
52735
52736 dispose() {
52737
52738 this.geometry.dispose();
52739 this.material.dispose();
52740
52741 }
52742
52743 }
52744
52745 class ShapePath {
52746
52747 constructor() {
52748
52749 this.type = 'ShapePath';
52750
52751 this.color = new Color();
52752
52753 this.subPaths = [];
52754 this.currentPath = null;
52755
52756 }
52757
52758 moveTo( x, y ) {
52759
52760 this.currentPath = new Path();
52761 this.subPaths.push( this.currentPath );
52762 this.currentPath.moveTo( x, y );
52763
52764 return this;
52765
52766 }
52767
52768 lineTo( x, y ) {
52769
52770 this.currentPath.lineTo( x, y );
52771
52772 return this;
52773
52774 }
52775
52776 quadraticCurveTo( aCPx, aCPy, aX, aY ) {
52777
52778 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );
52779
52780 return this;
52781
52782 }
52783
52784 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {
52785
52786 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );
52787
52788 return this;
52789
52790 }
52791
52792 splineThru( pts ) {
52793
52794 this.currentPath.splineThru( pts );
52795
52796 return this;
52797
52798 }
52799
52800 toShapes( isCCW ) {
52801
52802 function toShapesNoHoles( inSubpaths ) {
52803
52804 const shapes = [];
52805
52806 for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {
52807
52808 const tmpPath = inSubpaths[ i ];
52809
52810 const tmpShape = new Shape();
52811 tmpShape.curves = tmpPath.curves;
52812
52813 shapes.push( tmpShape );
52814
52815 }
52816
52817 return shapes;
52818
52819 }
52820
52821 function isPointInsidePolygon( inPt, inPolygon ) {
52822
52823 const polyLen = inPolygon.length;
52824
52825 // inPt on polygon contour => immediate success or
52826 // toggling of inside/outside at every single! intersection point of an edge
52827 // with the horizontal line through inPt, left of inPt
52828 // not counting lowerY endpoints of edges and whole edges on that line
52829 let inside = false;
52830 for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
52831
52832 let edgeLowPt = inPolygon[ p ];
52833 let edgeHighPt = inPolygon[ q ];
52834
52835 let edgeDx = edgeHighPt.x - edgeLowPt.x;
52836 let edgeDy = edgeHighPt.y - edgeLowPt.y;
52837
52838 if ( Math.abs( edgeDy ) > Number.EPSILON ) {
52839
52840 // not parallel
52841 if ( edgeDy < 0 ) {
52842
52843 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
52844 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
52845
52846 }
52847
52848 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
52849
52850 if ( inPt.y === edgeLowPt.y ) {
52851
52852 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ?
52853 // continue; // no intersection or edgeLowPt => doesn't count !!!
52854
52855 } else {
52856
52857 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );
52858 if ( perpEdge === 0 ) return true; // inPt is on contour ?
52859 if ( perpEdge < 0 ) continue;
52860 inside = ! inside; // true intersection left of inPt
52861
52862 }
52863
52864 } else {
52865
52866 // parallel or collinear
52867 if ( inPt.y !== edgeLowPt.y ) continue; // parallel
52868 // edge lies on the same horizontal line as inPt
52869 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
52870 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
52871 // continue;
52872
52873 }
52874
52875 }
52876
52877 return inside;
52878
52879 }
52880
52881 const isClockWise = ShapeUtils.isClockWise;
52882
52883 const subPaths = this.subPaths;
52884 if ( subPaths.length === 0 ) return [];
52885
52886 let solid, tmpPath, tmpShape;
52887 const shapes = [];
52888
52889 if ( subPaths.length === 1 ) {
52890
52891 tmpPath = subPaths[ 0 ];
52892 tmpShape = new Shape();
52893 tmpShape.curves = tmpPath.curves;
52894 shapes.push( tmpShape );
52895 return shapes;
52896
52897 }
52898
52899 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );
52900 holesFirst = isCCW ? ! holesFirst : holesFirst;
52901
52902 // console.log("Holes first", holesFirst);
52903
52904 const betterShapeHoles = [];
52905 const newShapes = [];
52906 let newShapeHoles = [];
52907 let mainIdx = 0;
52908 let tmpPoints;
52909
52910 newShapes[ mainIdx ] = undefined;
52911 newShapeHoles[ mainIdx ] = [];
52912
52913 for ( let i = 0, l = subPaths.length; i < l; i ++ ) {
52914
52915 tmpPath = subPaths[ i ];
52916 tmpPoints = tmpPath.getPoints();
52917 solid = isClockWise( tmpPoints );
52918 solid = isCCW ? ! solid : solid;
52919
52920 if ( solid ) {
52921
52922 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++;
52923
52924 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };
52925 newShapes[ mainIdx ].s.curves = tmpPath.curves;
52926
52927 if ( holesFirst ) mainIdx ++;
52928 newShapeHoles[ mainIdx ] = [];
52929
52930 //console.log('cw', i);
52931
52932 } else {
52933
52934 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );
52935
52936 //console.log('ccw', i);
52937
52938 }
52939
52940 }
52941
52942 // only Holes? -> probably all Shapes with wrong orientation
52943 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths );
52944
52945
52946 if ( newShapes.length > 1 ) {
52947
52948 let ambiguous = false;
52949 let toChange = 0;
52950
52951 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52952
52953 betterShapeHoles[ sIdx ] = [];
52954
52955 }
52956
52957 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
52958
52959 const sho = newShapeHoles[ sIdx ];
52960
52961 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {
52962
52963 const ho = sho[ hIdx ];
52964 let hole_unassigned = true;
52965
52966 for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
52967
52968 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {
52969
52970 if ( sIdx !== s2Idx ) toChange ++;
52971
52972 if ( hole_unassigned ) {
52973
52974 hole_unassigned = false;
52975 betterShapeHoles[ s2Idx ].push( ho );
52976
52977 } else {
52978
52979 ambiguous = true;
52980
52981 }
52982
52983 }
52984
52985 }
52986
52987 if ( hole_unassigned ) {
52988
52989 betterShapeHoles[ sIdx ].push( ho );
52990
52991 }
52992
52993 }
52994
52995 }
52996
52997 if ( toChange > 0 && ambiguous === false ) {
52998
52999 newShapeHoles = betterShapeHoles;
53000
53001 }
53002
53003 }
53004
53005 let tmpHoles;
53006
53007 for ( let i = 0, il = newShapes.length; i < il; i ++ ) {
53008
53009 tmpShape = newShapes[ i ].s;
53010 shapes.push( tmpShape );
53011 tmpHoles = newShapeHoles[ i ];
53012
53013 for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
53014
53015 tmpShape.holes.push( tmpHoles[ j ].h );
53016
53017 }
53018
53019 }
53020
53021 //console.log("shape", shapes);
53022
53023 return shapes;
53024
53025 }
53026
53027 }
53028
53029 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
53030
53031 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
53032 revision: REVISION,
53033 } } ) );
53034
53035 }
53036
53037 if ( typeof window !== 'undefined' ) {
53038
53039 if ( window.__THREE__ ) {
53040
53041 console.warn( 'WARNING: Multiple instances of Three.js being imported.' );
53042
53043 } else {
53044
53045 window.__THREE__ = REVISION;
53046
53047 }
53048
53049 }
53050
53051 exports.ACESFilmicToneMapping = ACESFilmicToneMapping;
53052 exports.AddEquation = AddEquation;
53053 exports.AddOperation = AddOperation;
53054 exports.AdditiveAnimationBlendMode = AdditiveAnimationBlendMode;
53055 exports.AdditiveBlending = AdditiveBlending;
53056 exports.AgXToneMapping = AgXToneMapping;
53057 exports.AlphaFormat = AlphaFormat;
53058 exports.AlwaysCompare = AlwaysCompare;
53059 exports.AlwaysDepth = AlwaysDepth;
53060 exports.AlwaysStencilFunc = AlwaysStencilFunc;
53061 exports.AmbientLight = AmbientLight;
53062 exports.AnimationAction = AnimationAction;
53063 exports.AnimationClip = AnimationClip;
53064 exports.AnimationLoader = AnimationLoader;
53065 exports.AnimationMixer = AnimationMixer;
53066 exports.AnimationObjectGroup = AnimationObjectGroup;
53067 exports.AnimationUtils = AnimationUtils;
53068 exports.ArcCurve = ArcCurve;
53069 exports.ArrayCamera = ArrayCamera;
53070 exports.ArrowHelper = ArrowHelper;
53071 exports.AttachedBindMode = AttachedBindMode;
53072 exports.Audio = Audio;
53073 exports.AudioAnalyser = AudioAnalyser;
53074 exports.AudioContext = AudioContext;
53075 exports.AudioListener = AudioListener;
53076 exports.AudioLoader = AudioLoader;
53077 exports.AxesHelper = AxesHelper;
53078 exports.BackSide = BackSide;
53079 exports.BasicDepthPacking = BasicDepthPacking;
53080 exports.BasicShadowMap = BasicShadowMap;
53081 exports.BatchedMesh = BatchedMesh;
53082 exports.Bone = Bone;
53083 exports.BooleanKeyframeTrack = BooleanKeyframeTrack;
53084 exports.Box2 = Box2;
53085 exports.Box3 = Box3;
53086 exports.Box3Helper = Box3Helper;
53087 exports.BoxGeometry = BoxGeometry;
53088 exports.BoxHelper = BoxHelper;
53089 exports.BufferAttribute = BufferAttribute;
53090 exports.BufferGeometry = BufferGeometry;
53091 exports.BufferGeometryLoader = BufferGeometryLoader;
53092 exports.ByteType = ByteType;
53093 exports.Cache = Cache;
53094 exports.Camera = Camera;
53095 exports.CameraHelper = CameraHelper;
53096 exports.CanvasTexture = CanvasTexture;
53097 exports.CapsuleGeometry = CapsuleGeometry;
53098 exports.CatmullRomCurve3 = CatmullRomCurve3;
53099 exports.CineonToneMapping = CineonToneMapping;
53100 exports.CircleGeometry = CircleGeometry;
53101 exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
53102 exports.Clock = Clock;
53103 exports.Color = Color;
53104 exports.ColorKeyframeTrack = ColorKeyframeTrack;
53105 exports.ColorManagement = ColorManagement;
53106 exports.CompressedArrayTexture = CompressedArrayTexture;
53107 exports.CompressedCubeTexture = CompressedCubeTexture;
53108 exports.CompressedTexture = CompressedTexture;
53109 exports.CompressedTextureLoader = CompressedTextureLoader;
53110 exports.ConeGeometry = ConeGeometry;
53111 exports.ConstantAlphaFactor = ConstantAlphaFactor;
53112 exports.ConstantColorFactor = ConstantColorFactor;
53113 exports.CubeCamera = CubeCamera;
53114 exports.CubeReflectionMapping = CubeReflectionMapping;
53115 exports.CubeRefractionMapping = CubeRefractionMapping;
53116 exports.CubeTexture = CubeTexture;
53117 exports.CubeTextureLoader = CubeTextureLoader;
53118 exports.CubeUVReflectionMapping = CubeUVReflectionMapping;
53119 exports.CubicBezierCurve = CubicBezierCurve;
53120 exports.CubicBezierCurve3 = CubicBezierCurve3;
53121 exports.CubicInterpolant = CubicInterpolant;
53122 exports.CullFaceBack = CullFaceBack;
53123 exports.CullFaceFront = CullFaceFront;
53124 exports.CullFaceFrontBack = CullFaceFrontBack;
53125 exports.CullFaceNone = CullFaceNone;
53126 exports.Curve = Curve;
53127 exports.CurvePath = CurvePath;
53128 exports.CustomBlending = CustomBlending;
53129 exports.CustomToneMapping = CustomToneMapping;
53130 exports.CylinderGeometry = CylinderGeometry;
53131 exports.Cylindrical = Cylindrical;
53132 exports.Data3DTexture = Data3DTexture;
53133 exports.DataArrayTexture = DataArrayTexture;
53134 exports.DataTexture = DataTexture;
53135 exports.DataTextureLoader = DataTextureLoader;
53136 exports.DataUtils = DataUtils;
53137 exports.DecrementStencilOp = DecrementStencilOp;
53138 exports.DecrementWrapStencilOp = DecrementWrapStencilOp;
53139 exports.DefaultLoadingManager = DefaultLoadingManager;
53140 exports.DepthFormat = DepthFormat;
53141 exports.DepthStencilFormat = DepthStencilFormat;
53142 exports.DepthTexture = DepthTexture;
53143 exports.DetachedBindMode = DetachedBindMode;
53144 exports.DirectionalLight = DirectionalLight;
53145 exports.DirectionalLightHelper = DirectionalLightHelper;
53146 exports.DiscreteInterpolant = DiscreteInterpolant;
53147 exports.DisplayP3ColorSpace = DisplayP3ColorSpace;
53148 exports.DodecahedronGeometry = DodecahedronGeometry;
53149 exports.DoubleSide = DoubleSide;
53150 exports.DstAlphaFactor = DstAlphaFactor;
53151 exports.DstColorFactor = DstColorFactor;
53152 exports.DynamicCopyUsage = DynamicCopyUsage;
53153 exports.DynamicDrawUsage = DynamicDrawUsage;
53154 exports.DynamicReadUsage = DynamicReadUsage;
53155 exports.EdgesGeometry = EdgesGeometry;
53156 exports.EllipseCurve = EllipseCurve;
53157 exports.EqualCompare = EqualCompare;
53158 exports.EqualDepth = EqualDepth;
53159 exports.EqualStencilFunc = EqualStencilFunc;
53160 exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;
53161 exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;
53162 exports.Euler = Euler;
53163 exports.EventDispatcher = EventDispatcher;
53164 exports.ExtrudeGeometry = ExtrudeGeometry;
53165 exports.FileLoader = FileLoader;
53166 exports.Float16BufferAttribute = Float16BufferAttribute;
53167 exports.Float32BufferAttribute = Float32BufferAttribute;
53168 exports.Float64BufferAttribute = Float64BufferAttribute;
53169 exports.FloatType = FloatType;
53170 exports.Fog = Fog;
53171 exports.FogExp2 = FogExp2;
53172 exports.FramebufferTexture = FramebufferTexture;
53173 exports.FrontSide = FrontSide;
53174 exports.Frustum = Frustum;
53175 exports.GLBufferAttribute = GLBufferAttribute;
53176 exports.GLSL1 = GLSL1;
53177 exports.GLSL3 = GLSL3;
53178 exports.GreaterCompare = GreaterCompare;
53179 exports.GreaterDepth = GreaterDepth;
53180 exports.GreaterEqualCompare = GreaterEqualCompare;
53181 exports.GreaterEqualDepth = GreaterEqualDepth;
53182 exports.GreaterEqualStencilFunc = GreaterEqualStencilFunc;
53183 exports.GreaterStencilFunc = GreaterStencilFunc;
53184 exports.GridHelper = GridHelper;
53185 exports.Group = Group;
53186 exports.HalfFloatType = HalfFloatType;
53187 exports.HemisphereLight = HemisphereLight;
53188 exports.HemisphereLightHelper = HemisphereLightHelper;
53189 exports.IcosahedronGeometry = IcosahedronGeometry;
53190 exports.ImageBitmapLoader = ImageBitmapLoader;
53191 exports.ImageLoader = ImageLoader;
53192 exports.ImageUtils = ImageUtils;
53193 exports.IncrementStencilOp = IncrementStencilOp;
53194 exports.IncrementWrapStencilOp = IncrementWrapStencilOp;
53195 exports.InstancedBufferAttribute = InstancedBufferAttribute;
53196 exports.InstancedBufferGeometry = InstancedBufferGeometry;
53197 exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;
53198 exports.InstancedMesh = InstancedMesh;
53199 exports.Int16BufferAttribute = Int16BufferAttribute;
53200 exports.Int32BufferAttribute = Int32BufferAttribute;
53201 exports.Int8BufferAttribute = Int8BufferAttribute;
53202 exports.IntType = IntType;
53203 exports.InterleavedBuffer = InterleavedBuffer;
53204 exports.InterleavedBufferAttribute = InterleavedBufferAttribute;
53205 exports.Interpolant = Interpolant;
53206 exports.InterpolateDiscrete = InterpolateDiscrete;
53207 exports.InterpolateLinear = InterpolateLinear;
53208 exports.InterpolateSmooth = InterpolateSmooth;
53209 exports.InvertStencilOp = InvertStencilOp;
53210 exports.KeepStencilOp = KeepStencilOp;
53211 exports.KeyframeTrack = KeyframeTrack;
53212 exports.LOD = LOD;
53213 exports.LatheGeometry = LatheGeometry;
53214 exports.Layers = Layers;
53215 exports.LessCompare = LessCompare;
53216 exports.LessDepth = LessDepth;
53217 exports.LessEqualCompare = LessEqualCompare;
53218 exports.LessEqualDepth = LessEqualDepth;
53219 exports.LessEqualStencilFunc = LessEqualStencilFunc;
53220 exports.LessStencilFunc = LessStencilFunc;
53221 exports.Light = Light;
53222 exports.LightProbe = LightProbe;
53223 exports.Line = Line;
53224 exports.Line3 = Line3;
53225 exports.LineBasicMaterial = LineBasicMaterial;
53226 exports.LineCurve = LineCurve;
53227 exports.LineCurve3 = LineCurve3;
53228 exports.LineDashedMaterial = LineDashedMaterial;
53229 exports.LineLoop = LineLoop;
53230 exports.LineSegments = LineSegments;
53231 exports.LinearDisplayP3ColorSpace = LinearDisplayP3ColorSpace;
53232 exports.LinearEncoding = LinearEncoding;
53233 exports.LinearFilter = LinearFilter;
53234 exports.LinearInterpolant = LinearInterpolant;
53235 exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;
53236 exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;
53237 exports.LinearMipmapLinearFilter = LinearMipmapLinearFilter;
53238 exports.LinearMipmapNearestFilter = LinearMipmapNearestFilter;
53239 exports.LinearSRGBColorSpace = LinearSRGBColorSpace;
53240 exports.LinearToneMapping = LinearToneMapping;
53241 exports.LinearTransfer = LinearTransfer;
53242 exports.Loader = Loader;
53243 exports.LoaderUtils = LoaderUtils;
53244 exports.LoadingManager = LoadingManager;
53245 exports.LoopOnce = LoopOnce;
53246 exports.LoopPingPong = LoopPingPong;
53247 exports.LoopRepeat = LoopRepeat;
53248 exports.LuminanceAlphaFormat = LuminanceAlphaFormat;
53249 exports.LuminanceFormat = LuminanceFormat;
53250 exports.MOUSE = MOUSE;
53251 exports.Material = Material;
53252 exports.MaterialLoader = MaterialLoader;
53253 exports.MathUtils = MathUtils;
53254 exports.Matrix3 = Matrix3;
53255 exports.Matrix4 = Matrix4;
53256 exports.MaxEquation = MaxEquation;
53257 exports.Mesh = Mesh;
53258 exports.MeshBasicMaterial = MeshBasicMaterial;
53259 exports.MeshDepthMaterial = MeshDepthMaterial;
53260 exports.MeshDistanceMaterial = MeshDistanceMaterial;
53261 exports.MeshLambertMaterial = MeshLambertMaterial;
53262 exports.MeshMatcapMaterial = MeshMatcapMaterial;
53263 exports.MeshNormalMaterial = MeshNormalMaterial;
53264 exports.MeshPhongMaterial = MeshPhongMaterial;
53265 exports.MeshPhysicalMaterial = MeshPhysicalMaterial;
53266 exports.MeshStandardMaterial = MeshStandardMaterial;
53267 exports.MeshToonMaterial = MeshToonMaterial;
53268 exports.MinEquation = MinEquation;
53269 exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
53270 exports.MixOperation = MixOperation;
53271 exports.MultiplyBlending = MultiplyBlending;
53272 exports.MultiplyOperation = MultiplyOperation;
53273 exports.NearestFilter = NearestFilter;
53274 exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;
53275 exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
53276 exports.NearestMipmapLinearFilter = NearestMipmapLinearFilter;
53277 exports.NearestMipmapNearestFilter = NearestMipmapNearestFilter;
53278 exports.NeverCompare = NeverCompare;
53279 exports.NeverDepth = NeverDepth;
53280 exports.NeverStencilFunc = NeverStencilFunc;
53281 exports.NoBlending = NoBlending;
53282 exports.NoColorSpace = NoColorSpace;
53283 exports.NoToneMapping = NoToneMapping;
53284 exports.NormalAnimationBlendMode = NormalAnimationBlendMode;
53285 exports.NormalBlending = NormalBlending;
53286 exports.NotEqualCompare = NotEqualCompare;
53287 exports.NotEqualDepth = NotEqualDepth;
53288 exports.NotEqualStencilFunc = NotEqualStencilFunc;
53289 exports.NumberKeyframeTrack = NumberKeyframeTrack;
53290 exports.Object3D = Object3D;
53291 exports.ObjectLoader = ObjectLoader;
53292 exports.ObjectSpaceNormalMap = ObjectSpaceNormalMap;
53293 exports.OctahedronGeometry = OctahedronGeometry;
53294 exports.OneFactor = OneFactor;
53295 exports.OneMinusConstantAlphaFactor = OneMinusConstantAlphaFactor;
53296 exports.OneMinusConstantColorFactor = OneMinusConstantColorFactor;
53297 exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;
53298 exports.OneMinusDstColorFactor = OneMinusDstColorFactor;
53299 exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;
53300 exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;
53301 exports.OrthographicCamera = OrthographicCamera;
53302 exports.P3Primaries = P3Primaries;
53303 exports.PCFShadowMap = PCFShadowMap;
53304 exports.PCFSoftShadowMap = PCFSoftShadowMap;
53305 exports.PMREMGenerator = PMREMGenerator;
53306 exports.Path = Path;
53307 exports.PerspectiveCamera = PerspectiveCamera;
53308 exports.Plane = Plane;
53309 exports.PlaneGeometry = PlaneGeometry;
53310 exports.PlaneHelper = PlaneHelper;
53311 exports.PointLight = PointLight;
53312 exports.PointLightHelper = PointLightHelper;
53313 exports.Points = Points;
53314 exports.PointsMaterial = PointsMaterial;
53315 exports.PolarGridHelper = PolarGridHelper;
53316 exports.PolyhedronGeometry = PolyhedronGeometry;
53317 exports.PositionalAudio = PositionalAudio;
53318 exports.PropertyBinding = PropertyBinding;
53319 exports.PropertyMixer = PropertyMixer;
53320 exports.QuadraticBezierCurve = QuadraticBezierCurve;
53321 exports.QuadraticBezierCurve3 = QuadraticBezierCurve3;
53322 exports.Quaternion = Quaternion;
53323 exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;
53324 exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;
53325 exports.RED_GREEN_RGTC2_Format = RED_GREEN_RGTC2_Format;
53326 exports.RED_RGTC1_Format = RED_RGTC1_Format;
53327 exports.REVISION = REVISION;
53328 exports.RGBADepthPacking = RGBADepthPacking;
53329 exports.RGBAFormat = RGBAFormat;
53330 exports.RGBAIntegerFormat = RGBAIntegerFormat;
53331 exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format;
53332 exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format;
53333 exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format;
53334 exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format;
53335 exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format;
53336 exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format;
53337 exports.RGBA_ASTC_4x4_Format = RGBA_ASTC_4x4_Format;
53338 exports.RGBA_ASTC_5x4_Format = RGBA_ASTC_5x4_Format;
53339 exports.RGBA_ASTC_5x5_Format = RGBA_ASTC_5x5_Format;
53340 exports.RGBA_ASTC_6x5_Format = RGBA_ASTC_6x5_Format;
53341 exports.RGBA_ASTC_6x6_Format = RGBA_ASTC_6x6_Format;
53342 exports.RGBA_ASTC_8x5_Format = RGBA_ASTC_8x5_Format;
53343 exports.RGBA_ASTC_8x6_Format = RGBA_ASTC_8x6_Format;
53344 exports.RGBA_ASTC_8x8_Format = RGBA_ASTC_8x8_Format;
53345 exports.RGBA_BPTC_Format = RGBA_BPTC_Format;
53346 exports.RGBA_ETC2_EAC_Format = RGBA_ETC2_EAC_Format;
53347 exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;
53348 exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
53349 exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
53350 exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
53351 exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
53352 exports.RGB_BPTC_SIGNED_Format = RGB_BPTC_SIGNED_Format;
53353 exports.RGB_BPTC_UNSIGNED_Format = RGB_BPTC_UNSIGNED_Format;
53354 exports.RGB_ETC1_Format = RGB_ETC1_Format;
53355 exports.RGB_ETC2_Format = RGB_ETC2_Format;
53356 exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
53357 exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;
53358 exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;
53359 exports.RGFormat = RGFormat;
53360 exports.RGIntegerFormat = RGIntegerFormat;
53361 exports.RawShaderMaterial = RawShaderMaterial;
53362 exports.Ray = Ray;
53363 exports.Raycaster = Raycaster;
53364 exports.Rec709Primaries = Rec709Primaries;
53365 exports.RectAreaLight = RectAreaLight;
53366 exports.RedFormat = RedFormat;
53367 exports.RedIntegerFormat = RedIntegerFormat;
53368 exports.ReinhardToneMapping = ReinhardToneMapping;
53369 exports.RenderTarget = RenderTarget;
53370 exports.RepeatWrapping = RepeatWrapping;
53371 exports.ReplaceStencilOp = ReplaceStencilOp;
53372 exports.ReverseSubtractEquation = ReverseSubtractEquation;
53373 exports.RingGeometry = RingGeometry;
53374 exports.SIGNED_RED_GREEN_RGTC2_Format = SIGNED_RED_GREEN_RGTC2_Format;
53375 exports.SIGNED_RED_RGTC1_Format = SIGNED_RED_RGTC1_Format;
53376 exports.SRGBColorSpace = SRGBColorSpace;
53377 exports.SRGBTransfer = SRGBTransfer;
53378 exports.Scene = Scene;
53379 exports.ShaderChunk = ShaderChunk;
53380 exports.ShaderLib = ShaderLib;
53381 exports.ShaderMaterial = ShaderMaterial;
53382 exports.ShadowMaterial = ShadowMaterial;
53383 exports.Shape = Shape;
53384 exports.ShapeGeometry = ShapeGeometry;
53385 exports.ShapePath = ShapePath;
53386 exports.ShapeUtils = ShapeUtils;
53387 exports.ShortType = ShortType;
53388 exports.Skeleton = Skeleton;
53389 exports.SkeletonHelper = SkeletonHelper;
53390 exports.SkinnedMesh = SkinnedMesh;
53391 exports.Source = Source;
53392 exports.Sphere = Sphere;
53393 exports.SphereGeometry = SphereGeometry;
53394 exports.Spherical = Spherical;
53395 exports.SphericalHarmonics3 = SphericalHarmonics3;
53396 exports.SplineCurve = SplineCurve;
53397 exports.SpotLight = SpotLight;
53398 exports.SpotLightHelper = SpotLightHelper;
53399 exports.Sprite = Sprite;
53400 exports.SpriteMaterial = SpriteMaterial;
53401 exports.SrcAlphaFactor = SrcAlphaFactor;
53402 exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;
53403 exports.SrcColorFactor = SrcColorFactor;
53404 exports.StaticCopyUsage = StaticCopyUsage;
53405 exports.StaticDrawUsage = StaticDrawUsage;
53406 exports.StaticReadUsage = StaticReadUsage;
53407 exports.StereoCamera = StereoCamera;
53408 exports.StreamCopyUsage = StreamCopyUsage;
53409 exports.StreamDrawUsage = StreamDrawUsage;
53410 exports.StreamReadUsage = StreamReadUsage;
53411 exports.StringKeyframeTrack = StringKeyframeTrack;
53412 exports.SubtractEquation = SubtractEquation;
53413 exports.SubtractiveBlending = SubtractiveBlending;
53414 exports.TOUCH = TOUCH;
53415 exports.TangentSpaceNormalMap = TangentSpaceNormalMap;
53416 exports.TetrahedronGeometry = TetrahedronGeometry;
53417 exports.Texture = Texture;
53418 exports.TextureLoader = TextureLoader;
53419 exports.TorusGeometry = TorusGeometry;
53420 exports.TorusKnotGeometry = TorusKnotGeometry;
53421 exports.Triangle = Triangle;
53422 exports.TriangleFanDrawMode = TriangleFanDrawMode;
53423 exports.TriangleStripDrawMode = TriangleStripDrawMode;
53424 exports.TrianglesDrawMode = TrianglesDrawMode;
53425 exports.TubeGeometry = TubeGeometry;
53426 exports.TwoPassDoubleSide = TwoPassDoubleSide;
53427 exports.UVMapping = UVMapping;
53428 exports.Uint16BufferAttribute = Uint16BufferAttribute;
53429 exports.Uint32BufferAttribute = Uint32BufferAttribute;
53430 exports.Uint8BufferAttribute = Uint8BufferAttribute;
53431 exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;
53432 exports.Uniform = Uniform;
53433 exports.UniformsGroup = UniformsGroup;
53434 exports.UniformsLib = UniformsLib;
53435 exports.UniformsUtils = UniformsUtils;
53436 exports.UnsignedByteType = UnsignedByteType;
53437 exports.UnsignedInt248Type = UnsignedInt248Type;
53438 exports.UnsignedIntType = UnsignedIntType;
53439 exports.UnsignedShort4444Type = UnsignedShort4444Type;
53440 exports.UnsignedShort5551Type = UnsignedShort5551Type;
53441 exports.UnsignedShortType = UnsignedShortType;
53442 exports.VSMShadowMap = VSMShadowMap;
53443 exports.Vector2 = Vector2;
53444 exports.Vector3 = Vector3;
53445 exports.Vector4 = Vector4;
53446 exports.VectorKeyframeTrack = VectorKeyframeTrack;
53447 exports.VideoTexture = VideoTexture;
53448 exports.WebGL1Renderer = WebGL1Renderer;
53449 exports.WebGL3DRenderTarget = WebGL3DRenderTarget;
53450 exports.WebGLArrayRenderTarget = WebGLArrayRenderTarget;
53451 exports.WebGLCoordinateSystem = WebGLCoordinateSystem;
53452 exports.WebGLCubeRenderTarget = WebGLCubeRenderTarget;
53453 exports.WebGLMultipleRenderTargets = WebGLMultipleRenderTargets;
53454 exports.WebGLRenderTarget = WebGLRenderTarget;
53455 exports.WebGLRenderer = WebGLRenderer;
53456 exports.WebGLUtils = WebGLUtils;
53457 exports.WebGPUCoordinateSystem = WebGPUCoordinateSystem;
53458 exports.WireframeGeometry = WireframeGeometry;
53459 exports.WrapAroundEnding = WrapAroundEnding;
53460 exports.ZeroCurvatureEnding = ZeroCurvatureEnding;
53461 exports.ZeroFactor = ZeroFactor;
53462 exports.ZeroSlopeEnding = ZeroSlopeEnding;
53463 exports.ZeroStencilOp = ZeroStencilOp;
53464 exports._SRGBAFormat = _SRGBAFormat;
53465 exports.createCanvasElement = createCanvasElement;
53466 exports.sRGBEncoding = sRGBEncoding;
53467
53468}));
OpenLayers Number
Definition OpenLayers.js:61
OpenLayers Projection transform
OpenLayers Util getParameters
Definition OpenLayers.js:99
OpenLayers Format GML v3
OpenLayers Protocol Response
OpenLayers String
Definition OpenLayers.js:59
OpenLayers Array
Definition OpenLayers.js:64
OpenLayers Bounds fromArray
Definition OpenLayers.js:75
OpenLayers Layer Google cache
OpenLayers Geometry
OpenLayers INCHES_PER_UNIT degrees
OpenLayers Feature Vector style
OpenLayers Map
OpenLayers Layer Google v2
OpenLayers Format XML document
OpenLayers Geometry Curve
function f
OpenLayers Format WFST v1
OpenLayers Util indexOf
Definition OpenLayers.js:83
function undefined
if(!$.ui||!$.ui.widget)
function factory
var max
var round
function x(t, e, i)
Definition leaflet.js:5
var re
Definition leaflet.js:5
this
Definition leaflet.js:5
var ae
Definition leaflet.js:5
function g(t, e)
Definition leaflet.js:5
function N()
Definition leaflet.js:5
et et include
Definition leaflet.js:5
function z(t, e)
Definition leaflet.js:5
function m(t, e, i)
Definition leaflet.js:5
function w(t, e, i)
Definition leaflet.js:5
function t
Definition leaflet.js:5
var B
Definition leaflet.js:5
function k(t, e, i, n)
Definition leaflet.js:5
function be(t, e, i)
Definition leaflet.js:5
function l(t)
Definition leaflet.js:5
var n
Definition leaflet.js:5
var o
Definition leaflet.js:5
function q(t, i)
Definition leaflet.js:5
var de
Definition leaflet.js:5
function u()
Definition leaflet.js:5
function dt(t, e)
Definition leaflet.js:5
function T(t)
Definition leaflet.js:5
function v(t, e, i)
Definition leaflet.js:5
function te(t)
Definition leaflet.js:5
function h(t)
Definition leaflet.js:5
function i(t, e)
Definition leaflet.js:5
function P(t, e, i)
Definition leaflet.js:5
var $
Definition leaflet.js:5
var ce
Definition leaflet.js:5
var A
Definition leaflet.js:5
function y(t)
Definition leaflet.js:5
var b
Definition leaflet.js:5
var e
Definition leaflet.js:5
function me(t)
Definition leaflet.js:5
var pt
Definition leaflet.js:5
function p(t, e, i)
Definition leaflet.js:5
function at(t, e, i, n)
Definition leaflet.js:5
function r(t)
Definition leaflet.js:5
var it
Definition leaflet.js:5
var d
Definition leaflet.js:5
function s(t, e)
Definition leaflet.js:5
function j(t, e, i)
Definition leaflet.js:5
var version
THREE RGBA_S3TC_DXT3_Format
Definition three.min1.js:6
THREE ReverseSubtractEquation
Definition three.min1.js:3
THREE CustomBlending
Definition three.min1.js:3
THREE BackSide
Definition three.min1.js:2
THREE ArrowHelper prototype setLength
THREE CullFaceFrontBack
Definition three.min1.js:2
THREE Path prototype absellipse
THREE ShaderChunk envmap_vertex
THREE CurvePath prototype closePath
THREE Camera prototype lookAt
THREE Sprite
THREE LuminanceAlphaFormat
Definition three.min1.js:5
THREE MeshLambertMaterial
THREE IntType
Definition three.min1.js:5
THREE AddOperation
Definition three.min1.js:4
THREE PerspectiveCamera prototype setViewOffset
THREE Skeleton prototype pose
THREE Mesh
THREE CubicBezierCurve
THREE ShaderChunk morphnormal_vertex
THREE Fog
THREE Texture
THREE ShaderChunk envmap_pars_vertex
THREE NearestMipMapNearestFilter
Definition three.min1.js:4
THREE SplineCurve
THREE Path prototype bezierCurveTo
THREE Curve prototype getUtoTmapping
THREE CurvePath prototype getCurveLengths
THREE LineCurve3
THREE ShaderChunk color_fragment
THREE CurvePath
THREE BufferGeometry
var THREE
Definition three.min1.js:2
THREE ShaderChunk defaultnormal_vertex
THREE Camera
THREE NearestFilter
Definition three.min1.js:4
THREE RGBA_S3TC_DXT1_Format
Definition three.min1.js:6
THREE ShaderChunk color_vertex
THREE Matrix3
Definition three.min1.js:85
THREE ShaderChunk envmap_pars_fragment
THREE Frustum
THREE LineDashedMaterial
THREE Bone prototype updateMatrixWorld
THREE LineBasicMaterial
THREE CurvePath prototype getBoundingBox
THREE DefaultLoadingManager
THREE OneMinusSrcColorFactor
Definition three.min1.js:3
THREE ShaderChunk morphtarget_vertex
THREE DstColorFactor
Definition three.min1.js:3
THREE FloatType
Definition three.min1.js:5
THREE IcosahedronGeometry
THREE SubtractiveBlending
Definition three.min1.js:3
THREE ShaderChunk logdepthbuf_pars_fragment
THREE Animation prototype stop
THREE Path prototype quadraticCurveTo
THREE FrontSide
Definition three.min1.js:2
THREE Triangle normal
THREE ShaderChunk specularmap_pars_fragment
THREE ImageUtils
THREE MultiplyBlending
Definition three.min1.js:3
THREE OctahedronGeometry
THREE MeshPhongMaterial
THREE ShaderChunk map_fragment
THREE UVMapping
Definition three.min1.js:4
THREE ShaderChunk alphamap_pars_fragment
THREE OneFactor
Definition three.min1.js:3
THREE Cache
THREE Curve prototype getTangentAt
THREE ShaderChunk morphtarget_pars_vertex
THREE FogExp2
THREE CompressedTexture
THREE PerspectiveCamera
THREE ShaderChunk skinbase_vertex
THREE AlphaFormat
Definition three.min1.js:5
THREE SpriteMaterial
THREE Skeleton
THREE Vector4
Definition three.min1.js:50
THREE RepeatWrapping
Definition three.min1.js:4
THREE TorusGeometry
THREE Loader
THREE WebGLRenderer
THREE EventDispatcher
THREE ShaderChunk logdepthbuf_fragment
THREE LinearMipMapLinearFilter
Definition three.min1.js:5
THREE Triangle containsPoint
THREE Material
THREE OneMinusDstAlphaFactor
Definition three.min1.js:3
THREE Curve prototype getLengths
THREE Curve prototype getPointAt
THREE CylinderGeometry
THREE Mesh prototype updateMorphTargets
THREE SrcColorFactor
Definition three.min1.js:3
THREE ShaderChunk lightmap_fragment
THREE RGB_S3TC_DXT1_Format
Definition three.min1.js:6
THREE Camera prototype clone
THREE ShaderChunk lights_phong_pars_fragment
THREE LuminanceFormat
Definition three.min1.js:5
THREE QuadraticBezierCurve3
THREE ShaderChunk skinnormal_vertex
THREE ShaderChunk lightmap_pars_fragment
THREE DirectionalLightHelper prototype dispose
THREE ShaderChunk map_particle_pars_fragment
THREE UnsignedShort5551Type
Definition three.min1.js:5
THREE Box3
Definition three.min1.js:77
THREE AdditiveBlending
Definition three.min1.js:3
THREE ShaderChunk color_pars_fragment
THREE PointCloud prototype raycast
THREE ShaderChunk skinning_pars_vertex
THREE PlaneGeometry
THREE LatheGeometry
THREE UnsignedIntType
Definition three.min1.js:5
THREE ClampToEdgeWrapping
Definition three.min1.js:4
THREE ShaderChunk fog_pars_fragment
THREE Curve prototype getLength
THREE LinearMipMapNearestFilter
Definition three.min1.js:5
THREE Path prototype absarc
THREE ShaderChunk normalmap_pars_fragment
THREE MeshNormalMaterial
THREE ShaderChunk color_pars_vertex
THREE Quaternion slerp
Definition three.min1.js:29
THREE CullFaceBack
Definition three.min1.js:2
THREE WebGLProgram
THREE Curve prototype getPoint
THREE Color
Definition three.min1.js:6
THREE LinearFilter
Definition three.min1.js:5
THREE UnsignedByteType
Definition three.min1.js:5
THREE BoxGeometry
THREE ShaderChunk alphatest_fragment
THREE ExtrudeGeometry prototype addShape
THREE Vector2
Definition three.min1.js:29
THREE ShaderChunk bumpmap_pars_fragment
THREE Scene
THREE SkinnedMesh prototype bind
THREE ArcCurve
THREE ShaderChunk envmap_fragment
THREE NearestMipMapLinearFilter
Definition three.min1.js:4
THREE SphereGeometry
THREE Sprite prototype updateMatrix
THREE CubicBezierCurve3
THREE ShaderChunk logdepthbuf_vertex
THREE Shape
THREE Path
THREE NoBlending
Definition three.min1.js:2
THREE Triangle
THREE ExtrudeGeometry
THREE MultiplyOperation
Definition three.min1.js:4
THREE UnsignedShortType
Definition three.min1.js:5
THREE Path prototype ellipse
THREE Plane
THREE TetrahedronGeometry
THREE PolyhedronGeometry
THREE BufferAttribute
THREE Ray
THREE MeshBasicMaterial
function a
THREE OrthographicCamera prototype updateProjectionMatrix
THREE PCFSoftShadowMap
Definition three.min1.js:2
THREE ByteType
Definition three.min1.js:5
THREE Matrix4
Definition three.min1.js:91
THREE Vector3
Definition three.min1.js:35
THREE ShaderChunk map_pars_fragment
THREE EllipseCurve
THREE ShaderChunk worldpos_vertex
THREE NormalBlending
Definition three.min1.js:3
THREE OrthographicCamera
THREE LineCurve
THREE SrcAlphaFactor
Definition three.min1.js:3
THREE Curve prototype getPoints
THREE SkinnedMesh
THREE WebGLShader
THREE ShaderChunk specularmap_fragment
THREE RingGeometry
THREE OneMinusDstColorFactor
Definition three.min1.js:3
THREE Object3D
THREE WebGLRenderTarget
THREE Path prototype splineThru
THREE Line
THREE Shape prototype getPointsHoles
THREE LOD prototype getObjectForDistance
THREE LoadingManager
THREE Path prototype lineTo
THREE DoubleSide
Definition three.min1.js:2
THREE ShaderChunk shadowmap_pars_fragment
THREE ShaderChunk alphamap_fragment
THREE JSONLoader prototype parse
THREE AddEquation
Definition three.min1.js:3
THREE BasicShadowMap
Definition three.min1.js:2
THREE LOD prototype addLevel
var c
THREE SkinnedMesh prototype normalizeSkinWeights
THREE SubtractEquation
Definition three.min1.js:3
THREE CubeTexture
THREE CullFaceFront
Definition three.min1.js:2
THREE Shape prototype extractPoints
THREE MixOperation
Definition three.min1.js:4
THREE TubeGeometry
THREE CullFaceNone
Definition three.min1.js:2
THREE ShaderChunk fog_fragment
THREE SrcAlphaSaturateFactor
Definition three.min1.js:4
THREE RGBAFormat
Definition three.min1.js:5
THREE ShaderChunk default_vertex
THREE Euler
Definition three.min1.js:61
THREE ShaderLib
THREE DstAlphaFactor
Definition three.min1.js:3
THREE Animation prototype reset
THREE ShaderChunk shadowmap_pars_vertex
object
Definition three.min1.js:2
THREE ShaderChunk
THREE MirroredRepeatWrapping
Definition three.min1.js:4
a Triangulate area
THREE Curve prototype getSpacedPoints
THREE ShapeGeometry
THREE CubeCamera
THREE DataTexture
THREE PCFShadowMap
Definition three.min1.js:2
THREE Curve prototype updateArcLengths
THREE UnsignedShort4444Type
Definition three.min1.js:5
THREE Quaternion
Definition three.min1.js:19
THREE Math
THREE Curve prototype getTangent
THREE ShaderChunk map_particle_fragment
THREE RGBA_S3TC_DXT5_Format
Definition three.min1.js:6
THREE ShortType
Definition three.min1.js:5
THREE LOD
THREE RawShaderMaterial
THREE Path prototype arc
THREE Path prototype moveTo
THREE ShaderChunk lights_phong_fragment
THREE ExtrudeGeometry WorldUVGenerator
THREE UniformsLib
THREE CubeReflectionMapping
Definition three.min1.js:4
THREE Bone
THREE CubeRefractionMapping
Definition three.min1.js:4
THREE ShaderChunk logdepthbuf_pars_vertex
THREE ShaderChunk shadowmap_vertex
THREE OneMinusSrcAlphaFactor
Definition three.min1.js:3
THREE CurvePath prototype add
THREE TorusKnotGeometry
THREE ShaderMaterial
THREE QuadraticBezierCurve
THREE JSONLoader prototype load
THREE CircleGeometry
THREE MeshDepthMaterial
THREE UniformsUtils
THREE Skeleton prototype update
THREE RenderableVertex prototype copy
THREE ZeroFactor
Definition three.min1.js:3
THREE ShaderChunk skinning_vertex
THREE Sphere
THREE Skeleton prototype calculateInverses
var Int32Array
Definition types.js:903
var Uint32Array
Definition types.js:904
var Uint8ClampedArray
Definition types.js:900
function global
Definition types.js:37
var Int8Array
Definition types.js:898
var pow
Definition types.js:73
var floor
Definition types.js:69
var Int16Array
Definition types.js:901
var Uint8Array
Definition types.js:899
var Uint16Array
Definition types.js:902
var log
Definition types.js:70
var Float32Array
Definition types.js:905
var min
Definition types.js:72
global DataView
Definition types.js:1026
var Float64Array
Definition types.js:906